Bug Summary

File:tools/lldb/source/Commands/CommandObjectType.cpp
Warning:line 2352, column 7
Potential leak of memory pointed to by 'options'

Annotated Source Code

Press '?' to see keyboard shortcuts

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