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