Bug Summary

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