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