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