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