Bug Summary

File:tools/lldb/source/Commands/CommandObjectType.cpp
Location:line 1414, column 9
Description:Potential leak of memory pointed to by 'options'

Annotated Source Code

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