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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of lldb/source/Commands/CommandObjectType.cpp