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