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 // Project includes 19 #include "lldb/Core/ConstString.h" 20 #include "lldb/Core/Debugger.h" 21 #include "lldb/Core/IOHandler.h" 22 #include "lldb/Core/RegularExpression.h" 23 #include "lldb/Core/State.h" 24 #include "lldb/Core/StringList.h" 25 #include "lldb/DataFormatters/DataVisualization.h" 26 #include "lldb/Interpreter/CommandInterpreter.h" 27 #include "lldb/Interpreter/CommandObject.h" 28 #include "lldb/Interpreter/CommandReturnObject.h" 29 #include "lldb/Interpreter/OptionGroupFormat.h" 30 #include "lldb/Interpreter/OptionValueBoolean.h" 31 #include "lldb/Interpreter/OptionValueLanguage.h" 32 #include "lldb/Interpreter/OptionValueString.h" 33 #include "lldb/Interpreter/Options.h" 34 #include "lldb/Symbol/Symbol.h" 35 #include "lldb/Target/Language.h" 36 #include "lldb/Target/Process.h" 37 #include "lldb/Target/StackFrame.h" 38 #include "lldb/Target/Target.h" 39 #include "lldb/Target/Thread.h" 40 #include "lldb/Target/ThreadList.h" 41 42 // Other libraries and framework includes 43 #include "llvm/ADT/STLExtras.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 if (command.empty()) 82 return false; 83 84 for (auto entry : llvm::enumerate(command.entries().drop_back())) { 85 if (entry.Value.ref != "unsigned") 86 continue; 87 auto next = command.entries()[entry.Index + 1].ref; 88 if (next == "int" || next == "short" || next == "char" || next == "long") { 89 result.AppendWarningWithFormat( 90 "unsigned %s being treated as two types. if you meant the combined " 91 "type " 92 "name use quotes, as in \"unsigned %s\"\n", 93 next.str().c_str(), next.str().c_str()); 94 return true; 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, llvm::StringRef 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(option_value, true, &success); 575 if (!success) 576 error.SetErrorStringWithFormat("invalid value for cascade: %s", 577 option_value.str().c_str()); 578 break; 579 case 'p': 580 m_skip_pointers = true; 581 break; 582 case 'w': 583 m_category.assign(option_value); 584 break; 585 case 'r': 586 m_skip_references = true; 587 break; 588 case 'x': 589 m_regex = true; 590 break; 591 case 't': 592 m_custom_type_name.assign(option_value); 593 break; 594 default: 595 error.SetErrorStringWithFormat("unrecognized option '%c'", 596 short_option); 597 break; 598 } 599 600 return error; 601 } 602 Error SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; 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 (auto &arg_entry : command.entries()) { 731 if (arg_entry.ref.empty()) { 732 result.AppendError("empty typenames not allowed"); 733 result.SetStatus(eReturnStatusFailed); 734 return false; 735 } 736 737 ConstString typeCS(arg_entry.ref); 738 if (m_command_options.m_regex) { 739 RegularExpressionSP typeRX(new RegularExpression()); 740 if (!typeRX->Compile(arg_entry.ref)) { 741 result.AppendError( 742 "regex format error (maybe this is not really a regex?)"); 743 result.SetStatus(eReturnStatusFailed); 744 return false; 745 } 746 category_sp->GetRegexTypeSummariesContainer()->Delete(typeCS); 747 category_sp->GetRegexTypeFormatsContainer()->Add(typeRX, entry); 748 } else 749 category_sp->GetTypeFormatsContainer()->Add(typeCS, entry); 750 } 751 752 result.SetStatus(eReturnStatusSuccessFinishNoResult); 753 return result.Succeeded(); 754 } 755 }; 756 757 static OptionDefinition g_type_formatter_delete_options[] = { 758 // clang-format off 759 { LLDB_OPT_SET_1, false, "all", 'a', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Delete from every category." }, 760 { LLDB_OPT_SET_2, false, "category", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Delete from given category." }, 761 { LLDB_OPT_SET_3, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Delete from given language's category." } 762 // clang-format on 763 }; 764 765 class CommandObjectTypeFormatterDelete : public CommandObjectParsed { 766 protected: 767 class CommandOptions : public Options { 768 public: 769 CommandOptions() : Options() {} 770 771 ~CommandOptions() override = default; 772 773 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 774 ExecutionContext *execution_context) override { 775 Error error; 776 const int short_option = m_getopt_table[option_idx].val; 777 778 switch (short_option) { 779 case 'a': 780 m_delete_all = true; 781 break; 782 case 'w': 783 m_category = std::string(option_arg); 784 break; 785 case 'l': 786 m_language = Language::GetLanguageTypeFromString( 787 llvm::StringRef::withNullAsEmpty(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 llvm::StringRef option_strref = 1035 llvm::StringRef::withNullAsEmpty(option_arg); 1036 switch (short_option) { 1037 case 'w': 1038 m_category_regex.SetCurrentValue(option_strref); 1039 m_category_regex.SetOptionWasSet(); 1040 break; 1041 case 'l': 1042 error = m_category_language.SetValueFromString(option_strref); 1043 if (error.Success()) 1044 m_category_language.SetOptionWasSet(); 1045 break; 1046 default: 1047 error.SetErrorStringWithFormat("unrecognized option '%c'", 1048 short_option); 1049 break; 1050 } 1051 1052 return error; 1053 } 1054 1055 void OptionParsingStarting(ExecutionContext *execution_context) override { 1056 m_category_regex.Clear(); 1057 m_category_language.Clear(); 1058 } 1059 1060 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1061 static OptionDefinition g_option_table[] = { 1062 // clang-format off 1063 {LLDB_OPT_SET_1, false, "category-regex", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Only show categories matching this filter."}, 1064 {LLDB_OPT_SET_2, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Only show the category for a specific language."} 1065 // clang-format on 1066 }; 1067 return llvm::ArrayRef<OptionDefinition>(g_option_table); 1068 } 1069 1070 // Instance variables to hold the values for command options. 1071 1072 OptionValueString m_category_regex; 1073 OptionValueLanguage m_category_language; 1074 }; 1075 1076 CommandOptions m_options; 1077 1078 Options *GetOptions() override { return &m_options; } 1079 1080 public: 1081 CommandObjectTypeFormatterList(CommandInterpreter &interpreter, 1082 const char *name, const char *help) 1083 : CommandObjectParsed(interpreter, name, help, nullptr), m_options() { 1084 CommandArgumentEntry type_arg; 1085 CommandArgumentData type_style_arg; 1086 1087 type_style_arg.arg_type = eArgTypeName; 1088 type_style_arg.arg_repetition = eArgRepeatOptional; 1089 1090 type_arg.push_back(type_style_arg); 1091 1092 m_arguments.push_back(type_arg); 1093 } 1094 1095 ~CommandObjectTypeFormatterList() override = default; 1096 1097 protected: 1098 virtual bool FormatterSpecificList(CommandReturnObject &result) { 1099 return false; 1100 } 1101 1102 bool DoExecute(Args &command, CommandReturnObject &result) override { 1103 const size_t argc = command.GetArgumentCount(); 1104 1105 std::unique_ptr<RegularExpression> category_regex; 1106 std::unique_ptr<RegularExpression> formatter_regex; 1107 1108 if (m_options.m_category_regex.OptionWasSet()) { 1109 category_regex.reset(new RegularExpression()); 1110 if (!category_regex->Compile( 1111 m_options.m_category_regex.GetCurrentValueAsRef())) { 1112 result.AppendErrorWithFormat( 1113 "syntax error in category regular expression '%s'", 1114 m_options.m_category_regex.GetCurrentValueAsRef().str().c_str()); 1115 result.SetStatus(eReturnStatusFailed); 1116 return false; 1117 } 1118 } 1119 1120 if (argc == 1) { 1121 const char *arg = command.GetArgumentAtIndex(0); 1122 formatter_regex.reset(new RegularExpression()); 1123 if (!formatter_regex->Compile(llvm::StringRef::withNullAsEmpty(arg))) { 1124 result.AppendErrorWithFormat("syntax error in regular expression '%s'", 1125 arg); 1126 result.SetStatus(eReturnStatusFailed); 1127 return false; 1128 } 1129 } 1130 1131 bool any_printed = false; 1132 1133 auto category_closure = [&result, &formatter_regex, &any_printed]( 1134 const lldb::TypeCategoryImplSP &category) -> void { 1135 result.GetOutputStream().Printf( 1136 "-----------------------\nCategory: %s%s\n-----------------------\n", 1137 category->GetName(), category->IsEnabled() ? "" : " (disabled)"); 1138 1139 TypeCategoryImpl::ForEachCallbacks<FormatterType> foreach; 1140 foreach 1141 .SetExact([&result, &formatter_regex, &any_printed]( 1142 ConstString name, 1143 const FormatterSharedPointer &format_sp) -> bool { 1144 if (formatter_regex) { 1145 bool escape = true; 1146 if (name.GetStringRef() == formatter_regex->GetText()) { 1147 escape = false; 1148 } else if (formatter_regex->Execute(name.GetStringRef())) { 1149 escape = false; 1150 } 1151 1152 if (escape) 1153 return true; 1154 } 1155 1156 any_printed = true; 1157 result.GetOutputStream().Printf("%s: %s\n", name.AsCString(), 1158 format_sp->GetDescription().c_str()); 1159 return true; 1160 }); 1161 1162 foreach 1163 .SetWithRegex([&result, &formatter_regex, &any_printed]( 1164 RegularExpressionSP regex_sp, 1165 const FormatterSharedPointer &format_sp) -> bool { 1166 if (formatter_regex) { 1167 bool escape = true; 1168 if (regex_sp->GetText() == formatter_regex->GetText()) { 1169 escape = false; 1170 } else if (formatter_regex->Execute(regex_sp->GetText())) { 1171 escape = false; 1172 } 1173 1174 if (escape) 1175 return true; 1176 } 1177 1178 any_printed = true; 1179 result.GetOutputStream().Printf("%s: %s\n", 1180 regex_sp->GetText().str().c_str(), 1181 format_sp->GetDescription().c_str()); 1182 return true; 1183 }); 1184 1185 category->ForEach(foreach); 1186 }; 1187 1188 if (m_options.m_category_language.OptionWasSet()) { 1189 lldb::TypeCategoryImplSP category_sp; 1190 DataVisualization::Categories::GetCategory( 1191 m_options.m_category_language.GetCurrentValue(), category_sp); 1192 if (category_sp) 1193 category_closure(category_sp); 1194 } else { 1195 DataVisualization::Categories::ForEach( 1196 [this, &command, &result, &category_regex, &formatter_regex, 1197 &category_closure]( 1198 const lldb::TypeCategoryImplSP &category) -> bool { 1199 if (category_regex) { 1200 bool escape = true; 1201 if (category->GetName() == category_regex->GetText()) { 1202 escape = false; 1203 } else if (category_regex->Execute( 1204 llvm::StringRef::withNullAsEmpty( 1205 category->GetName()))) { 1206 escape = false; 1207 } 1208 1209 if (escape) 1210 return true; 1211 } 1212 1213 category_closure(category); 1214 1215 return true; 1216 }); 1217 1218 any_printed = FormatterSpecificList(result) | any_printed; 1219 } 1220 1221 if (any_printed) 1222 result.SetStatus(eReturnStatusSuccessFinishResult); 1223 else { 1224 result.GetOutputStream().PutCString("no matching results found.\n"); 1225 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1226 } 1227 return result.Succeeded(); 1228 } 1229 }; 1230 1231 //------------------------------------------------------------------------- 1232 // CommandObjectTypeFormatList 1233 //------------------------------------------------------------------------- 1234 1235 class CommandObjectTypeFormatList 1236 : public CommandObjectTypeFormatterList<TypeFormatImpl> { 1237 public: 1238 CommandObjectTypeFormatList(CommandInterpreter &interpreter) 1239 : CommandObjectTypeFormatterList(interpreter, "type format list", 1240 "Show a list of current formats.") {} 1241 }; 1242 1243 #ifndef LLDB_DISABLE_PYTHON 1244 1245 //------------------------------------------------------------------------- 1246 // CommandObjectTypeSummaryAdd 1247 //------------------------------------------------------------------------- 1248 1249 #endif // LLDB_DISABLE_PYTHON 1250 1251 Error CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue( 1252 uint32_t option_idx, const char *option_arg, 1253 ExecutionContext *execution_context) { 1254 Error error; 1255 const int short_option = m_getopt_table[option_idx].val; 1256 bool success; 1257 1258 switch (short_option) { 1259 case 'C': 1260 m_flags.SetCascades(Args::StringToBoolean( 1261 llvm::StringRef::withNullAsEmpty(option_arg), true, &success)); 1262 if (!success) 1263 error.SetErrorStringWithFormat("invalid value for cascade: %s", 1264 option_arg); 1265 break; 1266 case 'e': 1267 m_flags.SetDontShowChildren(false); 1268 break; 1269 case 'h': 1270 m_flags.SetHideEmptyAggregates(true); 1271 break; 1272 case 'v': 1273 m_flags.SetDontShowValue(true); 1274 break; 1275 case 'c': 1276 m_flags.SetShowMembersOneLiner(true); 1277 break; 1278 case 's': 1279 m_format_string = std::string(option_arg); 1280 break; 1281 case 'p': 1282 m_flags.SetSkipPointers(true); 1283 break; 1284 case 'r': 1285 m_flags.SetSkipReferences(true); 1286 break; 1287 case 'x': 1288 m_regex = true; 1289 break; 1290 case 'n': 1291 m_name.SetCString(option_arg); 1292 break; 1293 case 'o': 1294 m_python_script = std::string(option_arg); 1295 m_is_add_script = true; 1296 break; 1297 case 'F': 1298 m_python_function = std::string(option_arg); 1299 m_is_add_script = true; 1300 break; 1301 case 'P': 1302 m_is_add_script = true; 1303 break; 1304 case 'w': 1305 m_category = std::string(option_arg); 1306 break; 1307 case 'O': 1308 m_flags.SetHideItemNames(true); 1309 break; 1310 default: 1311 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 1312 break; 1313 } 1314 1315 return error; 1316 } 1317 1318 void CommandObjectTypeSummaryAdd::CommandOptions::OptionParsingStarting( 1319 ExecutionContext *execution_context) { 1320 m_flags.Clear().SetCascades().SetDontShowChildren().SetDontShowValue(false); 1321 m_flags.SetShowMembersOneLiner(false) 1322 .SetSkipPointers(false) 1323 .SetSkipReferences(false) 1324 .SetHideItemNames(false); 1325 1326 m_regex = false; 1327 m_name.Clear(); 1328 m_python_script = ""; 1329 m_python_function = ""; 1330 m_format_string = ""; 1331 m_is_add_script = false; 1332 m_category = "default"; 1333 } 1334 1335 #ifndef LLDB_DISABLE_PYTHON 1336 1337 bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary( 1338 Args &command, CommandReturnObject &result) { 1339 const size_t argc = command.GetArgumentCount(); 1340 1341 if (argc < 1 && !m_options.m_name) { 1342 result.AppendErrorWithFormat("%s takes one or more args.\n", 1343 m_cmd_name.c_str()); 1344 result.SetStatus(eReturnStatusFailed); 1345 return false; 1346 } 1347 1348 TypeSummaryImplSP script_format; 1349 1350 if (!m_options.m_python_function 1351 .empty()) // we have a Python function ready to use 1352 { 1353 const char *funct_name = m_options.m_python_function.c_str(); 1354 if (!funct_name || !funct_name[0]) { 1355 result.AppendError("function name empty.\n"); 1356 result.SetStatus(eReturnStatusFailed); 1357 return false; 1358 } 1359 1360 std::string code = 1361 (" " + m_options.m_python_function + "(valobj,internal_dict)"); 1362 1363 script_format.reset( 1364 new ScriptSummaryFormat(m_options.m_flags, funct_name, code.c_str())); 1365 1366 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); 1367 1368 if (interpreter && !interpreter->CheckObjectExists(funct_name)) 1369 result.AppendWarningWithFormat( 1370 "The provided function \"%s\" does not exist - " 1371 "please define it before attempting to use this summary.\n", 1372 funct_name); 1373 } else if (!m_options.m_python_script 1374 .empty()) // we have a quick 1-line script, just use it 1375 { 1376 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); 1377 if (!interpreter) { 1378 result.AppendError("script interpreter missing - unable to generate " 1379 "function wrapper.\n"); 1380 result.SetStatus(eReturnStatusFailed); 1381 return false; 1382 } 1383 StringList funct_sl; 1384 funct_sl << m_options.m_python_script.c_str(); 1385 std::string funct_name_str; 1386 if (!interpreter->GenerateTypeScriptFunction(funct_sl, funct_name_str)) { 1387 result.AppendError("unable to generate function wrapper.\n"); 1388 result.SetStatus(eReturnStatusFailed); 1389 return false; 1390 } 1391 if (funct_name_str.empty()) { 1392 result.AppendError( 1393 "script interpreter failed to generate a valid function name.\n"); 1394 result.SetStatus(eReturnStatusFailed); 1395 return false; 1396 } 1397 1398 std::string code = " " + m_options.m_python_script; 1399 1400 script_format.reset(new ScriptSummaryFormat( 1401 m_options.m_flags, funct_name_str.c_str(), code.c_str())); 1402 } else { 1403 // Use an IOHandler to grab Python code from the user 1404 ScriptAddOptions *options = 1405 new ScriptAddOptions(m_options.m_flags, m_options.m_regex, 1406 m_options.m_name, m_options.m_category); 1407 1408 for (auto &entry : command.entries()) { 1409 if (entry.ref.empty()) { 1410 result.AppendError("empty typenames not allowed"); 1411 result.SetStatus(eReturnStatusFailed); 1412 return false; 1413 } 1414 1415 options->m_target_types << entry.ref; 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 (auto &entry : command.entries()) { 1435 CommandObjectTypeSummaryAdd::AddSummary( 1436 ConstString(entry.ref), script_format, 1437 (m_options.m_regex ? eRegexSummary : eRegularSummary), 1438 m_options.m_category, &error); 1439 if (error.Fail()) { 1440 result.AppendError(error.AsCString()); 1441 result.SetStatus(eReturnStatusFailed); 1442 return false; 1443 } 1444 } 1445 1446 if (m_options.m_name) { 1447 AddSummary(m_options.m_name, script_format, eNamedSummary, 1448 m_options.m_category, &error); 1449 if (error.Fail()) { 1450 result.AppendError(error.AsCString()); 1451 result.AppendError("added to types, but not given a name"); 1452 result.SetStatus(eReturnStatusFailed); 1453 return false; 1454 } 1455 } 1456 1457 return result.Succeeded(); 1458 } 1459 1460 #endif // LLDB_DISABLE_PYTHON 1461 1462 bool CommandObjectTypeSummaryAdd::Execute_StringSummary( 1463 Args &command, CommandReturnObject &result) { 1464 const size_t argc = command.GetArgumentCount(); 1465 1466 if (argc < 1 && !m_options.m_name) { 1467 result.AppendErrorWithFormat("%s takes one or more args.\n", 1468 m_cmd_name.c_str()); 1469 result.SetStatus(eReturnStatusFailed); 1470 return false; 1471 } 1472 1473 if (!m_options.m_flags.GetShowMembersOneLiner() && 1474 m_options.m_format_string.empty()) { 1475 result.AppendError("empty summary strings not allowed"); 1476 result.SetStatus(eReturnStatusFailed); 1477 return false; 1478 } 1479 1480 const char *format_cstr = (m_options.m_flags.GetShowMembersOneLiner() 1481 ? "" 1482 : m_options.m_format_string.c_str()); 1483 1484 // ${var%S} is an endless recursion, prevent it 1485 if (strcmp(format_cstr, "${var%S}") == 0) { 1486 result.AppendError("recursive summary not allowed"); 1487 result.SetStatus(eReturnStatusFailed); 1488 return false; 1489 } 1490 1491 std::unique_ptr<StringSummaryFormat> string_format( 1492 new StringSummaryFormat(m_options.m_flags, format_cstr)); 1493 if (!string_format) { 1494 result.AppendError("summary creation failed"); 1495 result.SetStatus(eReturnStatusFailed); 1496 return false; 1497 } 1498 if (string_format->m_error.Fail()) { 1499 result.AppendErrorWithFormat("syntax error: %s", 1500 string_format->m_error.AsCString("<unknown>")); 1501 result.SetStatus(eReturnStatusFailed); 1502 return false; 1503 } 1504 lldb::TypeSummaryImplSP entry(string_format.release()); 1505 1506 // now I have a valid format, let's add it to every type 1507 Error error; 1508 for (auto &arg_entry : command.entries()) { 1509 if (arg_entry.ref.empty()) { 1510 result.AppendError("empty typenames not allowed"); 1511 result.SetStatus(eReturnStatusFailed); 1512 return false; 1513 } 1514 ConstString typeCS(arg_entry.ref); 1515 1516 AddSummary(typeCS, entry, 1517 (m_options.m_regex ? eRegexSummary : eRegularSummary), 1518 m_options.m_category, &error); 1519 1520 if (error.Fail()) { 1521 result.AppendError(error.AsCString()); 1522 result.SetStatus(eReturnStatusFailed); 1523 return false; 1524 } 1525 } 1526 1527 if (m_options.m_name) { 1528 AddSummary(m_options.m_name, entry, eNamedSummary, m_options.m_category, 1529 &error); 1530 if (error.Fail()) { 1531 result.AppendError(error.AsCString()); 1532 result.AppendError("added to types, but not given a name"); 1533 result.SetStatus(eReturnStatusFailed); 1534 return false; 1535 } 1536 } 1537 1538 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1539 return result.Succeeded(); 1540 } 1541 1542 CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd( 1543 CommandInterpreter &interpreter) 1544 : CommandObjectParsed(interpreter, "type summary add", 1545 "Add a new summary style for a type.", nullptr), 1546 IOHandlerDelegateMultiline("DONE"), m_options(interpreter) { 1547 CommandArgumentEntry type_arg; 1548 CommandArgumentData type_style_arg; 1549 1550 type_style_arg.arg_type = eArgTypeName; 1551 type_style_arg.arg_repetition = eArgRepeatPlus; 1552 1553 type_arg.push_back(type_style_arg); 1554 1555 m_arguments.push_back(type_arg); 1556 1557 SetHelpLong( 1558 R"( 1559 The following examples of 'type summary add' refer to this code snippet for context: 1560 1561 struct JustADemo 1562 { 1563 int* ptr; 1564 float value; 1565 JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {} 1566 }; 1567 JustADemo demo_instance(42, 3.14); 1568 1569 typedef JustADemo NewDemo; 1570 NewDemo new_demo_instance(42, 3.14); 1571 1572 (lldb) type summary add --summary-string "the answer is ${*var.ptr}" JustADemo 1573 1574 Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42" 1575 1576 (lldb) type summary add --summary-string "the answer is ${*var.ptr}, and the question is ${var.value}" JustADemo 1577 1578 Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42 and the question is 3.14" 1579 1580 )" 1581 "Alternatively, you could define formatting for all pointers to integers and \ 1582 rely on that when formatting JustADemo to obtain the same result:" 1583 R"( 1584 1585 (lldb) type summary add --summary-string "${var%V} -> ${*var}" "int *" 1586 (lldb) type summary add --summary-string "the answer is ${var.ptr}, and the question is ${var.value}" JustADemo 1587 1588 )" 1589 "Type summaries are automatically applied to derived typedefs, so the examples \ 1590 above apply to both JustADemo and NewDemo. The cascade option can be used to \ 1591 suppress this behavior:" 1592 R"( 1593 1594 (lldb) type summary add --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo -C no 1595 1596 The summary will now be used for values of JustADemo but not NewDemo. 1597 1598 )" 1599 "By default summaries are shown for pointers and references to values of the \ 1600 specified type. To suppress formatting for pointers use the -p option, or apply \ 1601 the corresponding -r option to suppress formatting for references:" 1602 R"( 1603 1604 (lldb) type summary add -p -r --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo 1605 1606 )" 1607 "One-line summaries including all fields in a type can be inferred without supplying an \ 1608 explicit summary string by passing the -c option:" 1609 R"( 1610 1611 (lldb) type summary add -c JustADemo 1612 (lldb) frame variable demo_instance 1613 (ptr=<address>, value=3.14) 1614 1615 )" 1616 "Type summaries normally suppress the nested display of individual fields. To \ 1617 supply a summary to supplement the default structure add the -e option:" 1618 R"( 1619 1620 (lldb) type summary add -e --summary-string "*ptr = ${*var.ptr}" JustADemo 1621 1622 )" 1623 "Now when displaying JustADemo values the int* is displayed, followed by the \ 1624 standard LLDB sequence of children, one per line:" 1625 R"( 1626 1627 *ptr = 42 { 1628 ptr = <address> 1629 value = 3.14 1630 } 1631 1632 )" 1633 "You can also add summaries written in Python. These scripts use lldb public API to \ 1634 gather information from your variables and produce a meaningful summary. To start a \ 1635 multi-line script use the -P option. The function declaration will be displayed along with \ 1636 a comment describing the two arguments. End your script with the word 'DONE' on a line by \ 1637 itself:" 1638 R"( 1639 1640 (lldb) type summary add JustADemo -P 1641 def function (valobj,internal_dict): 1642 """valobj: an SBValue which you want to provide a summary for 1643 internal_dict: an LLDB support object not to be used""" 1644 value = valobj.GetChildMemberWithName('value'); 1645 return 'My value is ' + value.GetValue(); 1646 DONE 1647 1648 Alternatively, the -o option can be used when providing a simple one-line Python script: 1649 1650 (lldb) type summary add JustADemo -o "value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();")"); 1651 } 1652 1653 bool CommandObjectTypeSummaryAdd::DoExecute(Args &command, 1654 CommandReturnObject &result) { 1655 WarnOnPotentialUnquotedUnsignedType(command, result); 1656 1657 if (m_options.m_is_add_script) { 1658 #ifndef LLDB_DISABLE_PYTHON 1659 return Execute_ScriptSummary(command, result); 1660 #else 1661 result.AppendError("python is disabled"); 1662 result.SetStatus(eReturnStatusFailed); 1663 return false; 1664 #endif // LLDB_DISABLE_PYTHON 1665 } 1666 1667 return Execute_StringSummary(command, result); 1668 } 1669 1670 static bool FixArrayTypeNameWithRegex(ConstString &type_name) { 1671 llvm::StringRef type_name_ref(type_name.GetStringRef()); 1672 1673 if (type_name_ref.endswith("[]")) { 1674 std::string type_name_str(type_name.GetCString()); 1675 type_name_str.resize(type_name_str.length() - 2); 1676 if (type_name_str.back() != ' ') 1677 type_name_str.append(" \\[[0-9]+\\]"); 1678 else 1679 type_name_str.append("\\[[0-9]+\\]"); 1680 type_name.SetCString(type_name_str.c_str()); 1681 return true; 1682 } 1683 return false; 1684 } 1685 1686 bool CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name, 1687 TypeSummaryImplSP entry, 1688 SummaryFormatType type, 1689 std::string category_name, 1690 Error *error) { 1691 lldb::TypeCategoryImplSP category; 1692 DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()), 1693 category); 1694 1695 if (type == eRegularSummary) { 1696 if (FixArrayTypeNameWithRegex(type_name)) 1697 type = eRegexSummary; 1698 } 1699 1700 if (type == eRegexSummary) { 1701 RegularExpressionSP typeRX(new RegularExpression()); 1702 if (!typeRX->Compile(type_name.GetStringRef())) { 1703 if (error) 1704 error->SetErrorString( 1705 "regex format error (maybe this is not really a regex?)"); 1706 return false; 1707 } 1708 1709 category->GetRegexTypeSummariesContainer()->Delete(type_name); 1710 category->GetRegexTypeSummariesContainer()->Add(typeRX, entry); 1711 1712 return true; 1713 } else if (type == eNamedSummary) { 1714 // system named summaries do not exist (yet?) 1715 DataVisualization::NamedSummaryFormats::Add(type_name, entry); 1716 return true; 1717 } else { 1718 category->GetTypeSummariesContainer()->Add(type_name, entry); 1719 return true; 1720 } 1721 } 1722 1723 //------------------------------------------------------------------------- 1724 // CommandObjectTypeSummaryDelete 1725 //------------------------------------------------------------------------- 1726 1727 class CommandObjectTypeSummaryDelete : public CommandObjectTypeFormatterDelete { 1728 public: 1729 CommandObjectTypeSummaryDelete(CommandInterpreter &interpreter) 1730 : CommandObjectTypeFormatterDelete( 1731 interpreter, 1732 eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary, 1733 "type summary delete", "Delete an existing summary for a type.") {} 1734 1735 ~CommandObjectTypeSummaryDelete() override = default; 1736 1737 protected: 1738 bool FormatterSpecificDeletion(ConstString typeCS) override { 1739 if (m_options.m_language != lldb::eLanguageTypeUnknown) 1740 return false; 1741 return DataVisualization::NamedSummaryFormats::Delete(typeCS); 1742 } 1743 }; 1744 1745 class CommandObjectTypeSummaryClear : public CommandObjectTypeFormatterClear { 1746 public: 1747 CommandObjectTypeSummaryClear(CommandInterpreter &interpreter) 1748 : CommandObjectTypeFormatterClear( 1749 interpreter, 1750 eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary, 1751 "type summary clear", "Delete all existing summaries.") {} 1752 1753 protected: 1754 void FormatterSpecificDeletion() override { 1755 DataVisualization::NamedSummaryFormats::Clear(); 1756 } 1757 }; 1758 1759 //------------------------------------------------------------------------- 1760 // CommandObjectTypeSummaryList 1761 //------------------------------------------------------------------------- 1762 1763 class CommandObjectTypeSummaryList 1764 : public CommandObjectTypeFormatterList<TypeSummaryImpl> { 1765 public: 1766 CommandObjectTypeSummaryList(CommandInterpreter &interpreter) 1767 : CommandObjectTypeFormatterList(interpreter, "type summary list", 1768 "Show a list of current summaries.") {} 1769 1770 protected: 1771 bool FormatterSpecificList(CommandReturnObject &result) override { 1772 if (DataVisualization::NamedSummaryFormats::GetCount() > 0) { 1773 result.GetOutputStream().Printf("Named summaries:\n"); 1774 DataVisualization::NamedSummaryFormats::ForEach( 1775 [&result](ConstString name, 1776 const TypeSummaryImplSP &summary_sp) -> bool { 1777 result.GetOutputStream().Printf( 1778 "%s: %s\n", name.AsCString(), 1779 summary_sp->GetDescription().c_str()); 1780 return true; 1781 }); 1782 return true; 1783 } 1784 return false; 1785 } 1786 }; 1787 1788 //------------------------------------------------------------------------- 1789 // CommandObjectTypeCategoryDefine 1790 //------------------------------------------------------------------------- 1791 1792 static OptionDefinition g_type_category_define_options[] = { 1793 // clang-format off 1794 { LLDB_OPT_SET_ALL, false, "enabled", 'e', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "If specified, this category will be created enabled." }, 1795 { LLDB_OPT_SET_ALL, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Specify the language that this category is supported for." } 1796 // clang-format on 1797 }; 1798 1799 class CommandObjectTypeCategoryDefine : public CommandObjectParsed { 1800 class CommandOptions : public Options { 1801 public: 1802 CommandOptions() 1803 : Options(), m_define_enabled(false, false), 1804 m_cate_language(eLanguageTypeUnknown, eLanguageTypeUnknown) {} 1805 1806 ~CommandOptions() override = default; 1807 1808 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 1809 ExecutionContext *execution_context) override { 1810 Error error; 1811 const int short_option = m_getopt_table[option_idx].val; 1812 1813 switch (short_option) { 1814 case 'e': 1815 m_define_enabled.SetValueFromString(llvm::StringRef("true")); 1816 break; 1817 case 'l': 1818 error = m_cate_language.SetValueFromString( 1819 llvm::StringRef::withNullAsEmpty(option_arg)); 1820 break; 1821 default: 1822 error.SetErrorStringWithFormat("unrecognized option '%c'", 1823 short_option); 1824 break; 1825 } 1826 1827 return error; 1828 } 1829 1830 void OptionParsingStarting(ExecutionContext *execution_context) override { 1831 m_define_enabled.Clear(); 1832 m_cate_language.Clear(); 1833 } 1834 1835 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1836 return llvm::makeArrayRef(g_type_category_define_options); 1837 } 1838 1839 // Instance variables to hold the values for command options. 1840 1841 OptionValueBoolean m_define_enabled; 1842 OptionValueLanguage m_cate_language; 1843 }; 1844 1845 CommandOptions m_options; 1846 1847 Options *GetOptions() override { return &m_options; } 1848 1849 public: 1850 CommandObjectTypeCategoryDefine(CommandInterpreter &interpreter) 1851 : CommandObjectParsed(interpreter, "type category define", 1852 "Define a new category as a source of formatters.", 1853 nullptr), 1854 m_options() { 1855 CommandArgumentEntry type_arg; 1856 CommandArgumentData type_style_arg; 1857 1858 type_style_arg.arg_type = eArgTypeName; 1859 type_style_arg.arg_repetition = eArgRepeatPlus; 1860 1861 type_arg.push_back(type_style_arg); 1862 1863 m_arguments.push_back(type_arg); 1864 } 1865 1866 ~CommandObjectTypeCategoryDefine() override = default; 1867 1868 protected: 1869 bool DoExecute(Args &command, CommandReturnObject &result) override { 1870 const size_t argc = command.GetArgumentCount(); 1871 1872 if (argc < 1) { 1873 result.AppendErrorWithFormat("%s takes 1 or more args.\n", 1874 m_cmd_name.c_str()); 1875 result.SetStatus(eReturnStatusFailed); 1876 return false; 1877 } 1878 1879 for (auto &entry : command.entries()) { 1880 TypeCategoryImplSP category_sp; 1881 if (DataVisualization::Categories::GetCategory(ConstString(entry.ref), 1882 category_sp) && 1883 category_sp) { 1884 category_sp->AddLanguage(m_options.m_cate_language.GetCurrentValue()); 1885 if (m_options.m_define_enabled.GetCurrentValue()) 1886 DataVisualization::Categories::Enable(category_sp, 1887 TypeCategoryMap::Default); 1888 } 1889 } 1890 1891 result.SetStatus(eReturnStatusSuccessFinishResult); 1892 return result.Succeeded(); 1893 } 1894 }; 1895 1896 //------------------------------------------------------------------------- 1897 // CommandObjectTypeCategoryEnable 1898 //------------------------------------------------------------------------- 1899 1900 static OptionDefinition g_type_category_enable_options[] = { 1901 // clang-format off 1902 { LLDB_OPT_SET_ALL, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Enable the category for this language." }, 1903 // clang-format on 1904 }; 1905 1906 class CommandObjectTypeCategoryEnable : public CommandObjectParsed { 1907 class CommandOptions : public Options { 1908 public: 1909 CommandOptions() : Options() {} 1910 1911 ~CommandOptions() override = default; 1912 1913 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 1914 ExecutionContext *execution_context) override { 1915 Error error; 1916 const int short_option = m_getopt_table[option_idx].val; 1917 1918 switch (short_option) { 1919 case 'l': 1920 if (option_arg) { 1921 m_language = Language::GetLanguageTypeFromString( 1922 llvm::StringRef::withNullAsEmpty(option_arg)); 1923 if (m_language == lldb::eLanguageTypeUnknown) 1924 error.SetErrorStringWithFormat("unrecognized language '%s'", 1925 option_arg); 1926 } 1927 break; 1928 default: 1929 error.SetErrorStringWithFormat("unrecognized option '%c'", 1930 short_option); 1931 break; 1932 } 1933 1934 return error; 1935 } 1936 1937 void OptionParsingStarting(ExecutionContext *execution_context) override { 1938 m_language = lldb::eLanguageTypeUnknown; 1939 } 1940 1941 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1942 return llvm::makeArrayRef(g_type_category_enable_options); 1943 } 1944 1945 // Instance variables to hold the values for command options. 1946 1947 lldb::LanguageType m_language; 1948 }; 1949 1950 CommandOptions m_options; 1951 1952 Options *GetOptions() override { return &m_options; } 1953 1954 public: 1955 CommandObjectTypeCategoryEnable(CommandInterpreter &interpreter) 1956 : CommandObjectParsed(interpreter, "type category enable", 1957 "Enable a category as a source of formatters.", 1958 nullptr), 1959 m_options() { 1960 CommandArgumentEntry type_arg; 1961 CommandArgumentData type_style_arg; 1962 1963 type_style_arg.arg_type = eArgTypeName; 1964 type_style_arg.arg_repetition = eArgRepeatPlus; 1965 1966 type_arg.push_back(type_style_arg); 1967 1968 m_arguments.push_back(type_arg); 1969 } 1970 1971 ~CommandObjectTypeCategoryEnable() override = default; 1972 1973 protected: 1974 bool DoExecute(Args &command, CommandReturnObject &result) override { 1975 const size_t argc = command.GetArgumentCount(); 1976 1977 if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) { 1978 result.AppendErrorWithFormat("%s takes arguments and/or a language", 1979 m_cmd_name.c_str()); 1980 result.SetStatus(eReturnStatusFailed); 1981 return false; 1982 } 1983 1984 if (argc == 1 && strcmp(command.GetArgumentAtIndex(0), "*") == 0) { 1985 DataVisualization::Categories::EnableStar(); 1986 } else if (argc > 0) { 1987 for (int i = argc - 1; i >= 0; i--) { 1988 const char *typeA = command.GetArgumentAtIndex(i); 1989 ConstString typeCS(typeA); 1990 1991 if (!typeCS) { 1992 result.AppendError("empty category name not allowed"); 1993 result.SetStatus(eReturnStatusFailed); 1994 return false; 1995 } 1996 DataVisualization::Categories::Enable(typeCS); 1997 lldb::TypeCategoryImplSP cate; 1998 if (DataVisualization::Categories::GetCategory(typeCS, cate) && cate) { 1999 if (cate->GetCount() == 0) { 2000 result.AppendWarning("empty category enabled (typo?)"); 2001 } 2002 } 2003 } 2004 } 2005 2006 if (m_options.m_language != lldb::eLanguageTypeUnknown) 2007 DataVisualization::Categories::Enable(m_options.m_language); 2008 2009 result.SetStatus(eReturnStatusSuccessFinishResult); 2010 return result.Succeeded(); 2011 } 2012 }; 2013 2014 //------------------------------------------------------------------------- 2015 // CommandObjectTypeCategoryDelete 2016 //------------------------------------------------------------------------- 2017 2018 class CommandObjectTypeCategoryDelete : public CommandObjectParsed { 2019 public: 2020 CommandObjectTypeCategoryDelete(CommandInterpreter &interpreter) 2021 : CommandObjectParsed(interpreter, "type category delete", 2022 "Delete a category and all associated formatters.", 2023 nullptr) { 2024 CommandArgumentEntry type_arg; 2025 CommandArgumentData type_style_arg; 2026 2027 type_style_arg.arg_type = eArgTypeName; 2028 type_style_arg.arg_repetition = eArgRepeatPlus; 2029 2030 type_arg.push_back(type_style_arg); 2031 2032 m_arguments.push_back(type_arg); 2033 } 2034 2035 ~CommandObjectTypeCategoryDelete() override = default; 2036 2037 protected: 2038 bool DoExecute(Args &command, CommandReturnObject &result) override { 2039 const size_t argc = command.GetArgumentCount(); 2040 2041 if (argc < 1) { 2042 result.AppendErrorWithFormat("%s takes 1 or more arg.\n", 2043 m_cmd_name.c_str()); 2044 result.SetStatus(eReturnStatusFailed); 2045 return false; 2046 } 2047 2048 bool success = true; 2049 2050 // the order is not relevant here 2051 for (int i = argc - 1; i >= 0; i--) { 2052 const char *typeA = command.GetArgumentAtIndex(i); 2053 ConstString typeCS(typeA); 2054 2055 if (!typeCS) { 2056 result.AppendError("empty category name not allowed"); 2057 result.SetStatus(eReturnStatusFailed); 2058 return false; 2059 } 2060 if (!DataVisualization::Categories::Delete(typeCS)) 2061 success = false; // keep deleting even if we hit an error 2062 } 2063 if (success) { 2064 result.SetStatus(eReturnStatusSuccessFinishResult); 2065 return result.Succeeded(); 2066 } else { 2067 result.AppendError("cannot delete one or more categories\n"); 2068 result.SetStatus(eReturnStatusFailed); 2069 return false; 2070 } 2071 } 2072 }; 2073 2074 //------------------------------------------------------------------------- 2075 // CommandObjectTypeCategoryDisable 2076 //------------------------------------------------------------------------- 2077 2078 OptionDefinition g_type_category_disable_options[] = { 2079 // clang-format off 2080 { LLDB_OPT_SET_ALL, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Enable the category for this language." } 2081 // clang-format on 2082 }; 2083 2084 class CommandObjectTypeCategoryDisable : public CommandObjectParsed { 2085 class CommandOptions : public Options { 2086 public: 2087 CommandOptions() : Options() {} 2088 2089 ~CommandOptions() override = default; 2090 2091 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 2092 ExecutionContext *execution_context) override { 2093 Error error; 2094 const int short_option = m_getopt_table[option_idx].val; 2095 2096 switch (short_option) { 2097 case 'l': 2098 if (option_arg) { 2099 m_language = Language::GetLanguageTypeFromString( 2100 llvm::StringRef::withNullAsEmpty(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 for (auto &entry : command.entries()) { 2357 if (entry.ref.empty()) { 2358 result.AppendError("empty typenames not allowed"); 2359 result.SetStatus(eReturnStatusFailed); 2360 return false; 2361 } 2362 2363 options->m_target_types << entry.ref; 2364 } 2365 2366 m_interpreter.GetPythonCommandsFromIOHandler( 2367 " ", // Prompt 2368 *this, // IOHandlerDelegate 2369 true, // Run IOHandler in async mode 2370 options); // Baton for the "io_handler" that will be passed back into our 2371 // IOHandlerDelegate functions 2372 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2373 return result.Succeeded(); 2374 } 2375 2376 bool CommandObjectTypeSynthAdd::Execute_PythonClass( 2377 Args &command, CommandReturnObject &result) { 2378 const size_t argc = command.GetArgumentCount(); 2379 2380 if (argc < 1) { 2381 result.AppendErrorWithFormat("%s takes one or more args.\n", 2382 m_cmd_name.c_str()); 2383 result.SetStatus(eReturnStatusFailed); 2384 return false; 2385 } 2386 2387 if (m_options.m_class_name.empty() && !m_options.m_input_python) { 2388 result.AppendErrorWithFormat("%s needs either a Python class name or -P to " 2389 "directly input Python code.\n", 2390 m_cmd_name.c_str()); 2391 result.SetStatus(eReturnStatusFailed); 2392 return false; 2393 } 2394 2395 SyntheticChildrenSP entry; 2396 2397 ScriptedSyntheticChildren *impl = new ScriptedSyntheticChildren( 2398 SyntheticChildren::Flags() 2399 .SetCascades(m_options.m_cascade) 2400 .SetSkipPointers(m_options.m_skip_pointers) 2401 .SetSkipReferences(m_options.m_skip_references), 2402 m_options.m_class_name.c_str()); 2403 2404 entry.reset(impl); 2405 2406 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); 2407 2408 if (interpreter && 2409 !interpreter->CheckObjectExists(impl->GetPythonClassName())) 2410 result.AppendWarning("The provided class does not exist - please define it " 2411 "before attempting to use this synthetic provider"); 2412 2413 // now I have a valid provider, let's add it to every type 2414 2415 lldb::TypeCategoryImplSP category; 2416 DataVisualization::Categories::GetCategory( 2417 ConstString(m_options.m_category.c_str()), category); 2418 2419 Error error; 2420 2421 for (auto &arg_entry : command.entries()) { 2422 if (arg_entry.ref.empty()) { 2423 result.AppendError("empty typenames not allowed"); 2424 result.SetStatus(eReturnStatusFailed); 2425 return false; 2426 } 2427 2428 ConstString typeCS(arg_entry.ref); 2429 if (!AddSynth(typeCS, entry, 2430 m_options.m_regex ? eRegexSynth : eRegularSynth, 2431 m_options.m_category, &error)) { 2432 result.AppendError(error.AsCString()); 2433 result.SetStatus(eReturnStatusFailed); 2434 return false; 2435 } 2436 } 2437 2438 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2439 return result.Succeeded(); 2440 } 2441 2442 CommandObjectTypeSynthAdd::CommandObjectTypeSynthAdd( 2443 CommandInterpreter &interpreter) 2444 : CommandObjectParsed(interpreter, "type synthetic add", 2445 "Add a new synthetic provider for a type.", nullptr), 2446 IOHandlerDelegateMultiline("DONE"), m_options() { 2447 CommandArgumentEntry type_arg; 2448 CommandArgumentData type_style_arg; 2449 2450 type_style_arg.arg_type = eArgTypeName; 2451 type_style_arg.arg_repetition = eArgRepeatPlus; 2452 2453 type_arg.push_back(type_style_arg); 2454 2455 m_arguments.push_back(type_arg); 2456 } 2457 2458 bool CommandObjectTypeSynthAdd::AddSynth(ConstString type_name, 2459 SyntheticChildrenSP entry, 2460 SynthFormatType type, 2461 std::string category_name, 2462 Error *error) { 2463 lldb::TypeCategoryImplSP category; 2464 DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()), 2465 category); 2466 2467 if (type == eRegularSynth) { 2468 if (FixArrayTypeNameWithRegex(type_name)) 2469 type = eRegexSynth; 2470 } 2471 2472 if (category->AnyMatches(type_name, eFormatCategoryItemFilter | 2473 eFormatCategoryItemRegexFilter, 2474 false)) { 2475 if (error) 2476 error->SetErrorStringWithFormat("cannot add synthetic for type %s when " 2477 "filter is defined in same category!", 2478 type_name.AsCString()); 2479 return false; 2480 } 2481 2482 if (type == eRegexSynth) { 2483 RegularExpressionSP typeRX(new RegularExpression()); 2484 if (!typeRX->Compile(type_name.GetStringRef())) { 2485 if (error) 2486 error->SetErrorString( 2487 "regex format error (maybe this is not really a regex?)"); 2488 return false; 2489 } 2490 2491 category->GetRegexTypeSyntheticsContainer()->Delete(type_name); 2492 category->GetRegexTypeSyntheticsContainer()->Add(typeRX, entry); 2493 2494 return true; 2495 } else { 2496 category->GetTypeSyntheticsContainer()->Add(type_name, entry); 2497 return true; 2498 } 2499 } 2500 2501 #endif // LLDB_DISABLE_PYTHON 2502 2503 static OptionDefinition g_type_filter_add_options[] = { 2504 // clang-format off 2505 { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, cascade through typedef chains." }, 2506 { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects." }, 2507 { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for references-to-type objects." }, 2508 { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Add this to the given category instead of the default one." }, 2509 { LLDB_OPT_SET_ALL, false, "child", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpressionPath, "Include this expression path in the synthetic view." }, 2510 { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Type names are actually regular expressions." } 2511 // clang-format on 2512 }; 2513 2514 class CommandObjectTypeFilterAdd : public CommandObjectParsed { 2515 private: 2516 class CommandOptions : public Options { 2517 typedef std::vector<std::string> option_vector; 2518 2519 public: 2520 CommandOptions() : Options() {} 2521 2522 ~CommandOptions() override = default; 2523 2524 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 2525 ExecutionContext *execution_context) override { 2526 Error error; 2527 const int short_option = m_getopt_table[option_idx].val; 2528 bool success; 2529 2530 switch (short_option) { 2531 case 'C': 2532 m_cascade = Args::StringToBoolean( 2533 llvm::StringRef::withNullAsEmpty(option_arg), true, &success); 2534 if (!success) 2535 error.SetErrorStringWithFormat("invalid value for cascade: %s", 2536 option_arg); 2537 break; 2538 case 'c': 2539 m_expr_paths.push_back(option_arg); 2540 has_child_list = true; 2541 break; 2542 case 'p': 2543 m_skip_pointers = true; 2544 break; 2545 case 'r': 2546 m_skip_references = true; 2547 break; 2548 case 'w': 2549 m_category = std::string(option_arg); 2550 break; 2551 case 'x': 2552 m_regex = true; 2553 break; 2554 default: 2555 error.SetErrorStringWithFormat("unrecognized option '%c'", 2556 short_option); 2557 break; 2558 } 2559 2560 return error; 2561 } 2562 2563 void OptionParsingStarting(ExecutionContext *execution_context) override { 2564 m_cascade = true; 2565 m_skip_pointers = false; 2566 m_skip_references = false; 2567 m_category = "default"; 2568 m_expr_paths.clear(); 2569 has_child_list = false; 2570 m_regex = false; 2571 } 2572 2573 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2574 return llvm::makeArrayRef(g_type_filter_add_options); 2575 } 2576 2577 // Instance variables to hold the values for command options. 2578 2579 bool m_cascade; 2580 bool m_skip_references; 2581 bool m_skip_pointers; 2582 bool m_input_python; 2583 option_vector m_expr_paths; 2584 std::string m_category; 2585 bool has_child_list; 2586 bool m_regex; 2587 2588 typedef option_vector::iterator ExpressionPathsIterator; 2589 }; 2590 2591 CommandOptions m_options; 2592 2593 Options *GetOptions() override { return &m_options; } 2594 2595 enum FilterFormatType { eRegularFilter, eRegexFilter }; 2596 2597 bool AddFilter(ConstString type_name, TypeFilterImplSP entry, 2598 FilterFormatType type, std::string category_name, 2599 Error *error) { 2600 lldb::TypeCategoryImplSP category; 2601 DataVisualization::Categories::GetCategory( 2602 ConstString(category_name.c_str()), category); 2603 2604 if (type == eRegularFilter) { 2605 if (FixArrayTypeNameWithRegex(type_name)) 2606 type = eRegexFilter; 2607 } 2608 2609 if (category->AnyMatches(type_name, eFormatCategoryItemSynth | 2610 eFormatCategoryItemRegexSynth, 2611 false)) { 2612 if (error) 2613 error->SetErrorStringWithFormat("cannot add filter for type %s when " 2614 "synthetic is defined in same " 2615 "category!", 2616 type_name.AsCString()); 2617 return false; 2618 } 2619 2620 if (type == eRegexFilter) { 2621 RegularExpressionSP typeRX(new RegularExpression()); 2622 if (!typeRX->Compile(type_name.GetStringRef())) { 2623 if (error) 2624 error->SetErrorString( 2625 "regex format error (maybe this is not really a regex?)"); 2626 return false; 2627 } 2628 2629 category->GetRegexTypeFiltersContainer()->Delete(type_name); 2630 category->GetRegexTypeFiltersContainer()->Add(typeRX, entry); 2631 2632 return true; 2633 } else { 2634 category->GetTypeFiltersContainer()->Add(type_name, entry); 2635 return true; 2636 } 2637 } 2638 2639 public: 2640 CommandObjectTypeFilterAdd(CommandInterpreter &interpreter) 2641 : CommandObjectParsed(interpreter, "type filter add", 2642 "Add a new filter for a type.", nullptr), 2643 m_options() { 2644 CommandArgumentEntry type_arg; 2645 CommandArgumentData type_style_arg; 2646 2647 type_style_arg.arg_type = eArgTypeName; 2648 type_style_arg.arg_repetition = eArgRepeatPlus; 2649 2650 type_arg.push_back(type_style_arg); 2651 2652 m_arguments.push_back(type_arg); 2653 2654 SetHelpLong( 2655 R"( 2656 The following examples of 'type filter add' refer to this code snippet for context: 2657 2658 class Foo { 2659 int a; 2660 int b; 2661 int c; 2662 int d; 2663 int e; 2664 int f; 2665 int g; 2666 int h; 2667 int i; 2668 } 2669 Foo my_foo; 2670 2671 Adding a simple filter: 2672 2673 (lldb) type filter add --child a --child g Foo 2674 (lldb) frame variable my_foo 2675 2676 )" 2677 "Produces output where only a and g are displayed. Other children of my_foo \ 2678 (b, c, d, e, f, h and i) are available by asking for them explicitly:" 2679 R"( 2680 2681 (lldb) frame variable my_foo.b my_foo.c my_foo.i 2682 2683 )" 2684 "The formatting option --raw on frame variable bypasses the filter, showing \ 2685 all children of my_foo as if no filter was defined:" 2686 R"( 2687 2688 (lldb) frame variable my_foo --raw)"); 2689 } 2690 2691 ~CommandObjectTypeFilterAdd() override = default; 2692 2693 protected: 2694 bool DoExecute(Args &command, CommandReturnObject &result) override { 2695 const size_t argc = command.GetArgumentCount(); 2696 2697 if (argc < 1) { 2698 result.AppendErrorWithFormat("%s takes one or more args.\n", 2699 m_cmd_name.c_str()); 2700 result.SetStatus(eReturnStatusFailed); 2701 return false; 2702 } 2703 2704 if (m_options.m_expr_paths.empty()) { 2705 result.AppendErrorWithFormat("%s needs one or more children.\n", 2706 m_cmd_name.c_str()); 2707 result.SetStatus(eReturnStatusFailed); 2708 return false; 2709 } 2710 2711 TypeFilterImplSP entry(new TypeFilterImpl( 2712 SyntheticChildren::Flags() 2713 .SetCascades(m_options.m_cascade) 2714 .SetSkipPointers(m_options.m_skip_pointers) 2715 .SetSkipReferences(m_options.m_skip_references))); 2716 2717 // go through the expression paths 2718 CommandOptions::ExpressionPathsIterator begin, 2719 end = m_options.m_expr_paths.end(); 2720 2721 for (begin = m_options.m_expr_paths.begin(); begin != end; begin++) 2722 entry->AddExpressionPath(*begin); 2723 2724 // now I have a valid provider, let's add it to every type 2725 2726 lldb::TypeCategoryImplSP category; 2727 DataVisualization::Categories::GetCategory( 2728 ConstString(m_options.m_category.c_str()), category); 2729 2730 Error error; 2731 2732 WarnOnPotentialUnquotedUnsignedType(command, result); 2733 2734 for (auto &arg_entry : command.entries()) { 2735 if (arg_entry.ref.empty()) { 2736 result.AppendError("empty typenames not allowed"); 2737 result.SetStatus(eReturnStatusFailed); 2738 return false; 2739 } 2740 2741 ConstString typeCS(arg_entry.ref); 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 } 2750 2751 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2752 return result.Succeeded(); 2753 } 2754 }; 2755 2756 //---------------------------------------------------------------------- 2757 // "type lookup" 2758 //---------------------------------------------------------------------- 2759 static OptionDefinition g_type_lookup_options[] = { 2760 // clang-format off 2761 { LLDB_OPT_SET_ALL, false, "show-help", 'h', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display available help for types" }, 2762 { LLDB_OPT_SET_ALL, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Which language's types should the search scope be" } 2763 // clang-format on 2764 }; 2765 2766 class CommandObjectTypeLookup : public CommandObjectRaw { 2767 protected: 2768 // this function is allowed to do a more aggressive job at guessing languages 2769 // than the expression parser 2770 // is comfortable with - so leave the original call alone and add one that is 2771 // specific to type lookup 2772 lldb::LanguageType GuessLanguage(StackFrame *frame) { 2773 lldb::LanguageType lang_type = lldb::eLanguageTypeUnknown; 2774 2775 if (!frame) 2776 return lang_type; 2777 2778 lang_type = frame->GuessLanguage(); 2779 if (lang_type != lldb::eLanguageTypeUnknown) 2780 return lang_type; 2781 2782 Symbol *s = frame->GetSymbolContext(eSymbolContextSymbol).symbol; 2783 if (s) 2784 lang_type = s->GetMangled().GuessLanguage(); 2785 2786 return lang_type; 2787 } 2788 2789 class CommandOptions : public OptionGroup { 2790 public: 2791 CommandOptions() 2792 : OptionGroup(), m_show_help(false), m_language(eLanguageTypeUnknown) {} 2793 2794 ~CommandOptions() override = default; 2795 2796 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2797 return llvm::makeArrayRef(g_type_lookup_options); 2798 } 2799 2800 Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, 2801 ExecutionContext *execution_context) override { 2802 Error error; 2803 2804 const int short_option = g_type_lookup_options[option_idx].short_option; 2805 2806 switch (short_option) { 2807 case 'h': 2808 m_show_help = true; 2809 break; 2810 2811 case 'l': 2812 m_language = Language::GetLanguageTypeFromString(option_value); 2813 break; 2814 2815 default: 2816 error.SetErrorStringWithFormat("invalid short option character '%c'", 2817 short_option); 2818 break; 2819 } 2820 2821 return error; 2822 } 2823 Error SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; 2824 2825 void OptionParsingStarting(ExecutionContext *execution_context) override { 2826 m_show_help = false; 2827 m_language = eLanguageTypeUnknown; 2828 } 2829 2830 // Options table: Required for subclasses of Options. 2831 2832 bool m_show_help; 2833 lldb::LanguageType m_language; 2834 }; 2835 2836 OptionGroupOptions m_option_group; 2837 CommandOptions m_command_options; 2838 2839 public: 2840 CommandObjectTypeLookup(CommandInterpreter &interpreter) 2841 : CommandObjectRaw(interpreter, "type lookup", 2842 "Lookup types and declarations in the current target, " 2843 "following language-specific naming conventions.", 2844 "type lookup <type-specifier>", 2845 eCommandRequiresTarget), 2846 m_option_group(), m_command_options() { 2847 m_option_group.Append(&m_command_options); 2848 m_option_group.Finalize(); 2849 } 2850 2851 ~CommandObjectTypeLookup() override = default; 2852 2853 Options *GetOptions() override { return &m_option_group; } 2854 2855 const char *GetHelpLong() override { 2856 if (m_cmd_help_long.empty()) { 2857 StreamString stream; 2858 // FIXME: hardcoding languages is not good 2859 lldb::LanguageType languages[] = {eLanguageTypeObjC, 2860 eLanguageTypeC_plus_plus}; 2861 2862 for (const auto lang_type : languages) { 2863 if (auto language = Language::FindPlugin(lang_type)) { 2864 if (const char *help = 2865 language->GetLanguageSpecificTypeLookupHelp()) { 2866 stream.Printf("%s\n", help); 2867 } 2868 } 2869 } 2870 2871 if (stream.GetData()) 2872 m_cmd_help_long.assign(stream.GetString()); 2873 } 2874 return this->CommandObject::GetHelpLong(); 2875 } 2876 2877 bool DoExecute(const char *raw_command_line, 2878 CommandReturnObject &result) override { 2879 if (!raw_command_line || !raw_command_line[0]) { 2880 result.SetError( 2881 "type lookup cannot be invoked without a type name as argument"); 2882 return false; 2883 } 2884 2885 auto exe_ctx = GetCommandInterpreter().GetExecutionContext(); 2886 m_option_group.NotifyOptionParsingStarting(&exe_ctx); 2887 2888 const char *name_of_type = nullptr; 2889 2890 if (raw_command_line[0] == '-') { 2891 // We have some options and these options MUST end with --. 2892 const char *end_options = nullptr; 2893 const char *s = raw_command_line; 2894 while (s && s[0]) { 2895 end_options = ::strstr(s, "--"); 2896 if (end_options) { 2897 end_options += 2; // Get past the "--" 2898 if (::isspace(end_options[0])) { 2899 name_of_type = end_options; 2900 while (::isspace(*name_of_type)) 2901 ++name_of_type; 2902 break; 2903 } 2904 } 2905 s = end_options; 2906 } 2907 2908 if (end_options) { 2909 Args args( 2910 llvm::StringRef(raw_command_line, end_options - raw_command_line)); 2911 if (!ParseOptions(args, result)) 2912 return false; 2913 2914 Error error(m_option_group.NotifyOptionParsingFinished(&exe_ctx)); 2915 if (error.Fail()) { 2916 result.AppendError(error.AsCString()); 2917 result.SetStatus(eReturnStatusFailed); 2918 return false; 2919 } 2920 } 2921 } 2922 if (nullptr == name_of_type) 2923 name_of_type = raw_command_line; 2924 2925 // TargetSP 2926 // target_sp(GetCommandInterpreter().GetDebugger().GetSelectedTarget()); 2927 // const bool fill_all_in = true; 2928 // ExecutionContext exe_ctx(target_sp.get(), fill_all_in); 2929 ExecutionContextScope *best_scope = exe_ctx.GetBestExecutionContextScope(); 2930 2931 bool any_found = false; 2932 2933 std::vector<Language *> languages; 2934 2935 bool is_global_search = false; 2936 LanguageType guessed_language = lldb::eLanguageTypeUnknown; 2937 2938 if ((is_global_search = 2939 (m_command_options.m_language == eLanguageTypeUnknown))) { 2940 // FIXME: hardcoding languages is not good 2941 languages.push_back(Language::FindPlugin(eLanguageTypeObjC)); 2942 languages.push_back(Language::FindPlugin(eLanguageTypeC_plus_plus)); 2943 } else { 2944 languages.push_back(Language::FindPlugin(m_command_options.m_language)); 2945 } 2946 2947 // This is not the most efficient way to do this, but we support very few 2948 // languages 2949 // so the cost of the sort is going to be dwarfed by the actual lookup 2950 // anyway 2951 if (StackFrame *frame = m_exe_ctx.GetFramePtr()) { 2952 guessed_language = GuessLanguage(frame); 2953 if (guessed_language != eLanguageTypeUnknown) { 2954 std::sort( 2955 languages.begin(), languages.end(), 2956 [guessed_language](Language *lang1, Language *lang2) -> bool { 2957 if (!lang1 || !lang2) 2958 return false; 2959 LanguageType lt1 = lang1->GetLanguageType(); 2960 LanguageType lt2 = lang2->GetLanguageType(); 2961 if (lt1 == guessed_language) 2962 return true; // make the selected frame's language come first 2963 if (lt2 == guessed_language) 2964 return false; // make the selected frame's language come first 2965 return (lt1 < lt2); // normal comparison otherwise 2966 }); 2967 } 2968 } 2969 2970 bool is_first_language = true; 2971 2972 for (Language *language : languages) { 2973 if (!language) 2974 continue; 2975 2976 if (auto scavenger = language->GetTypeScavenger()) { 2977 Language::TypeScavenger::ResultSet search_results; 2978 if (scavenger->Find(best_scope, name_of_type, search_results) > 0) { 2979 for (const auto &search_result : search_results) { 2980 if (search_result && search_result->IsValid()) { 2981 any_found = true; 2982 search_result->DumpToStream(result.GetOutputStream(), 2983 this->m_command_options.m_show_help); 2984 } 2985 } 2986 } 2987 } 2988 // this is "type lookup SomeName" and we did find a match, so get out 2989 if (any_found && is_global_search) 2990 break; 2991 else if (is_first_language && is_global_search && 2992 guessed_language != lldb::eLanguageTypeUnknown) { 2993 is_first_language = false; 2994 result.GetOutputStream().Printf( 2995 "no type was found in the current language %s matching '%s'; " 2996 "performing a global search across all languages\n", 2997 Language::GetNameForLanguageType(guessed_language), name_of_type); 2998 } 2999 } 3000 3001 if (!any_found) 3002 result.AppendMessageWithFormat("no type was found matching '%s'\n", 3003 name_of_type); 3004 3005 result.SetStatus(any_found ? lldb::eReturnStatusSuccessFinishResult 3006 : lldb::eReturnStatusSuccessFinishNoResult); 3007 return true; 3008 } 3009 }; 3010 3011 template <typename FormatterType> 3012 class CommandObjectFormatterInfo : public CommandObjectRaw { 3013 public: 3014 typedef std::function<typename FormatterType::SharedPointer(ValueObject &)> 3015 DiscoveryFunction; 3016 CommandObjectFormatterInfo(CommandInterpreter &interpreter, 3017 const char *formatter_name, 3018 DiscoveryFunction discovery_func) 3019 : CommandObjectRaw(interpreter, "", "", "", 3020 eCommandRequiresFrame), 3021 m_formatter_name(formatter_name ? formatter_name : ""), 3022 m_discovery_function(discovery_func) { 3023 StreamString name; 3024 name.Printf("type %s info", formatter_name); 3025 SetCommandName(name.GetData()); 3026 StreamString help; 3027 help.Printf("This command evaluates the provided expression and shows " 3028 "which %s is applied to the resulting value (if any).", 3029 formatter_name); 3030 SetHelp(help.GetData()); 3031 StreamString syntax; 3032 syntax.Printf("type %s info <expr>", formatter_name); 3033 SetSyntax(syntax.GetData()); 3034 } 3035 3036 ~CommandObjectFormatterInfo() override = default; 3037 3038 protected: 3039 bool DoExecute(const char *command, CommandReturnObject &result) override { 3040 TargetSP target_sp = m_interpreter.GetDebugger().GetSelectedTarget(); 3041 Thread *thread = GetDefaultThread(); 3042 if (!thread) { 3043 result.AppendError("no default thread"); 3044 result.SetStatus(lldb::eReturnStatusFailed); 3045 return false; 3046 } 3047 3048 StackFrameSP frame_sp = thread->GetSelectedFrame(); 3049 ValueObjectSP result_valobj_sp; 3050 EvaluateExpressionOptions options; 3051 lldb::ExpressionResults expr_result = target_sp->EvaluateExpression( 3052 command, frame_sp.get(), result_valobj_sp, options); 3053 if (expr_result == eExpressionCompleted && result_valobj_sp) { 3054 result_valobj_sp = 3055 result_valobj_sp->GetQualifiedRepresentationIfAvailable( 3056 target_sp->GetPreferDynamicValue(), 3057 target_sp->GetEnableSyntheticValue()); 3058 typename FormatterType::SharedPointer formatter_sp = 3059 m_discovery_function(*result_valobj_sp); 3060 if (formatter_sp) { 3061 std::string description(formatter_sp->GetDescription()); 3062 result.AppendMessageWithFormat( 3063 "%s applied to (%s) %s is: %s\n", m_formatter_name.c_str(), 3064 result_valobj_sp->GetDisplayTypeName().AsCString("<unknown>"), 3065 command, description.c_str()); 3066 result.SetStatus(lldb::eReturnStatusSuccessFinishResult); 3067 } else { 3068 result.AppendMessageWithFormat( 3069 "no %s applies to (%s) %s\n", m_formatter_name.c_str(), 3070 result_valobj_sp->GetDisplayTypeName().AsCString("<unknown>"), 3071 command); 3072 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); 3073 } 3074 return true; 3075 } else { 3076 result.AppendError("failed to evaluate expression"); 3077 result.SetStatus(lldb::eReturnStatusFailed); 3078 return false; 3079 } 3080 } 3081 3082 private: 3083 std::string m_formatter_name; 3084 DiscoveryFunction m_discovery_function; 3085 }; 3086 3087 class CommandObjectTypeFormat : public CommandObjectMultiword { 3088 public: 3089 CommandObjectTypeFormat(CommandInterpreter &interpreter) 3090 : CommandObjectMultiword( 3091 interpreter, "type format", 3092 "Commands for customizing value display formats.", 3093 "type format [<sub-command-options>] ") { 3094 LoadSubCommand( 3095 "add", CommandObjectSP(new CommandObjectTypeFormatAdd(interpreter))); 3096 LoadSubCommand("clear", CommandObjectSP( 3097 new CommandObjectTypeFormatClear(interpreter))); 3098 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeFormatDelete( 3099 interpreter))); 3100 LoadSubCommand( 3101 "list", CommandObjectSP(new CommandObjectTypeFormatList(interpreter))); 3102 LoadSubCommand( 3103 "info", CommandObjectSP(new CommandObjectFormatterInfo<TypeFormatImpl>( 3104 interpreter, "format", 3105 [](ValueObject &valobj) -> TypeFormatImpl::SharedPointer { 3106 return valobj.GetValueFormat(); 3107 }))); 3108 } 3109 3110 ~CommandObjectTypeFormat() override = default; 3111 }; 3112 3113 #ifndef LLDB_DISABLE_PYTHON 3114 3115 class CommandObjectTypeSynth : public CommandObjectMultiword { 3116 public: 3117 CommandObjectTypeSynth(CommandInterpreter &interpreter) 3118 : CommandObjectMultiword( 3119 interpreter, "type synthetic", 3120 "Commands for operating on synthetic type representations.", 3121 "type synthetic [<sub-command-options>] ") { 3122 LoadSubCommand("add", 3123 CommandObjectSP(new CommandObjectTypeSynthAdd(interpreter))); 3124 LoadSubCommand( 3125 "clear", CommandObjectSP(new CommandObjectTypeSynthClear(interpreter))); 3126 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeSynthDelete( 3127 interpreter))); 3128 LoadSubCommand( 3129 "list", CommandObjectSP(new CommandObjectTypeSynthList(interpreter))); 3130 LoadSubCommand( 3131 "info", 3132 CommandObjectSP(new CommandObjectFormatterInfo<SyntheticChildren>( 3133 interpreter, "synthetic", 3134 [](ValueObject &valobj) -> SyntheticChildren::SharedPointer { 3135 return valobj.GetSyntheticChildren(); 3136 }))); 3137 } 3138 3139 ~CommandObjectTypeSynth() override = default; 3140 }; 3141 3142 #endif // LLDB_DISABLE_PYTHON 3143 3144 class CommandObjectTypeFilter : public CommandObjectMultiword { 3145 public: 3146 CommandObjectTypeFilter(CommandInterpreter &interpreter) 3147 : CommandObjectMultiword(interpreter, "type filter", 3148 "Commands for operating on type filters.", 3149 "type synthetic [<sub-command-options>] ") { 3150 LoadSubCommand( 3151 "add", CommandObjectSP(new CommandObjectTypeFilterAdd(interpreter))); 3152 LoadSubCommand("clear", CommandObjectSP( 3153 new CommandObjectTypeFilterClear(interpreter))); 3154 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeFilterDelete( 3155 interpreter))); 3156 LoadSubCommand( 3157 "list", CommandObjectSP(new CommandObjectTypeFilterList(interpreter))); 3158 } 3159 3160 ~CommandObjectTypeFilter() override = default; 3161 }; 3162 3163 class CommandObjectTypeCategory : public CommandObjectMultiword { 3164 public: 3165 CommandObjectTypeCategory(CommandInterpreter &interpreter) 3166 : CommandObjectMultiword(interpreter, "type category", 3167 "Commands for operating on type categories.", 3168 "type category [<sub-command-options>] ") { 3169 LoadSubCommand( 3170 "define", 3171 CommandObjectSP(new CommandObjectTypeCategoryDefine(interpreter))); 3172 LoadSubCommand( 3173 "enable", 3174 CommandObjectSP(new CommandObjectTypeCategoryEnable(interpreter))); 3175 LoadSubCommand( 3176 "disable", 3177 CommandObjectSP(new CommandObjectTypeCategoryDisable(interpreter))); 3178 LoadSubCommand( 3179 "delete", 3180 CommandObjectSP(new CommandObjectTypeCategoryDelete(interpreter))); 3181 LoadSubCommand("list", CommandObjectSP( 3182 new CommandObjectTypeCategoryList(interpreter))); 3183 } 3184 3185 ~CommandObjectTypeCategory() override = default; 3186 }; 3187 3188 class CommandObjectTypeSummary : public CommandObjectMultiword { 3189 public: 3190 CommandObjectTypeSummary(CommandInterpreter &interpreter) 3191 : CommandObjectMultiword( 3192 interpreter, "type summary", 3193 "Commands for editing variable summary display options.", 3194 "type summary [<sub-command-options>] ") { 3195 LoadSubCommand( 3196 "add", CommandObjectSP(new CommandObjectTypeSummaryAdd(interpreter))); 3197 LoadSubCommand("clear", CommandObjectSP(new CommandObjectTypeSummaryClear( 3198 interpreter))); 3199 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeSummaryDelete( 3200 interpreter))); 3201 LoadSubCommand( 3202 "list", CommandObjectSP(new CommandObjectTypeSummaryList(interpreter))); 3203 LoadSubCommand( 3204 "info", CommandObjectSP(new CommandObjectFormatterInfo<TypeSummaryImpl>( 3205 interpreter, "summary", 3206 [](ValueObject &valobj) -> TypeSummaryImpl::SharedPointer { 3207 return valobj.GetSummaryFormat(); 3208 }))); 3209 } 3210 3211 ~CommandObjectTypeSummary() override = default; 3212 }; 3213 3214 //------------------------------------------------------------------------- 3215 // CommandObjectType 3216 //------------------------------------------------------------------------- 3217 3218 CommandObjectType::CommandObjectType(CommandInterpreter &interpreter) 3219 : CommandObjectMultiword(interpreter, "type", 3220 "Commands for operating on the type system.", 3221 "type [<sub-command-options>]") { 3222 LoadSubCommand("category", 3223 CommandObjectSP(new CommandObjectTypeCategory(interpreter))); 3224 LoadSubCommand("filter", 3225 CommandObjectSP(new CommandObjectTypeFilter(interpreter))); 3226 LoadSubCommand("format", 3227 CommandObjectSP(new CommandObjectTypeFormat(interpreter))); 3228 LoadSubCommand("summary", 3229 CommandObjectSP(new CommandObjectTypeSummary(interpreter))); 3230 #ifndef LLDB_DISABLE_PYTHON 3231 LoadSubCommand("synthetic", 3232 CommandObjectSP(new CommandObjectTypeSynth(interpreter))); 3233 #endif // LLDB_DISABLE_PYTHON 3234 LoadSubCommand("lookup", 3235 CommandObjectSP(new CommandObjectTypeLookup(interpreter))); 3236 } 3237 3238 CommandObjectType::~CommandObjectType() = default; 3239