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