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