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