Bug Summary

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

Annotated Source Code

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