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