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