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