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