1 //===-- SBTypeCategory.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 "lldb/API/SBTypeCategory.h"
10 #include "lldb/Utility/Instrumentation.h"
11 
12 #include "lldb/API/SBStream.h"
13 #include "lldb/API/SBTypeFilter.h"
14 #include "lldb/API/SBTypeFormat.h"
15 #include "lldb/API/SBTypeNameSpecifier.h"
16 #include "lldb/API/SBTypeSummary.h"
17 #include "lldb/API/SBTypeSynthetic.h"
18 
19 #include "lldb/Core/Debugger.h"
20 #include "lldb/DataFormatters/DataVisualization.h"
21 #include "lldb/Interpreter/CommandInterpreter.h"
22 #include "lldb/Interpreter/ScriptInterpreter.h"
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 
27 typedef std::pair<lldb::TypeCategoryImplSP, user_id_t> ImplType;
28 
29 SBTypeCategory::SBTypeCategory() { LLDB_INSTRUMENT_VA(this); }
30 
31 SBTypeCategory::SBTypeCategory(const char *name) {
32   DataVisualization::Categories::GetCategory(ConstString(name), m_opaque_sp);
33 }
34 
35 SBTypeCategory::SBTypeCategory(const lldb::SBTypeCategory &rhs)
36     : m_opaque_sp(rhs.m_opaque_sp) {
37   LLDB_INSTRUMENT_VA(this, rhs);
38 }
39 
40 SBTypeCategory::~SBTypeCategory() = default;
41 
42 bool SBTypeCategory::IsValid() const {
43   LLDB_INSTRUMENT_VA(this);
44   return this->operator bool();
45 }
46 SBTypeCategory::operator bool() const {
47   LLDB_INSTRUMENT_VA(this);
48 
49   return (m_opaque_sp.get() != nullptr);
50 }
51 
52 bool SBTypeCategory::GetEnabled() {
53   LLDB_INSTRUMENT_VA(this);
54 
55   if (!IsValid())
56     return false;
57   return m_opaque_sp->IsEnabled();
58 }
59 
60 void SBTypeCategory::SetEnabled(bool enabled) {
61   LLDB_INSTRUMENT_VA(this, enabled);
62 
63   if (!IsValid())
64     return;
65   if (enabled)
66     DataVisualization::Categories::Enable(m_opaque_sp);
67   else
68     DataVisualization::Categories::Disable(m_opaque_sp);
69 }
70 
71 const char *SBTypeCategory::GetName() {
72   LLDB_INSTRUMENT_VA(this);
73 
74   if (!IsValid())
75     return nullptr;
76   return m_opaque_sp->GetName();
77 }
78 
79 lldb::LanguageType SBTypeCategory::GetLanguageAtIndex(uint32_t idx) {
80   LLDB_INSTRUMENT_VA(this, idx);
81 
82   if (IsValid())
83     return m_opaque_sp->GetLanguageAtIndex(idx);
84   return lldb::eLanguageTypeUnknown;
85 }
86 
87 uint32_t SBTypeCategory::GetNumLanguages() {
88   LLDB_INSTRUMENT_VA(this);
89 
90   if (IsValid())
91     return m_opaque_sp->GetNumLanguages();
92   return 0;
93 }
94 
95 void SBTypeCategory::AddLanguage(lldb::LanguageType language) {
96   LLDB_INSTRUMENT_VA(this, language);
97 
98   if (IsValid())
99     m_opaque_sp->AddLanguage(language);
100 }
101 
102 uint32_t SBTypeCategory::GetNumFormats() {
103   LLDB_INSTRUMENT_VA(this);
104 
105   if (!IsValid())
106     return 0;
107 
108   return m_opaque_sp->GetTypeFormatsContainer()->GetCount() +
109          m_opaque_sp->GetRegexTypeFormatsContainer()->GetCount();
110 }
111 
112 uint32_t SBTypeCategory::GetNumSummaries() {
113   LLDB_INSTRUMENT_VA(this);
114 
115   if (!IsValid())
116     return 0;
117   return m_opaque_sp->GetTypeSummariesContainer()->GetCount() +
118          m_opaque_sp->GetRegexTypeSummariesContainer()->GetCount();
119 }
120 
121 uint32_t SBTypeCategory::GetNumFilters() {
122   LLDB_INSTRUMENT_VA(this);
123 
124   if (!IsValid())
125     return 0;
126   return m_opaque_sp->GetTypeFiltersContainer()->GetCount() +
127          m_opaque_sp->GetRegexTypeFiltersContainer()->GetCount();
128 }
129 
130 uint32_t SBTypeCategory::GetNumSynthetics() {
131   LLDB_INSTRUMENT_VA(this);
132 
133   if (!IsValid())
134     return 0;
135   return m_opaque_sp->GetTypeSyntheticsContainer()->GetCount() +
136          m_opaque_sp->GetRegexTypeSyntheticsContainer()->GetCount();
137 }
138 
139 lldb::SBTypeNameSpecifier
140 SBTypeCategory::GetTypeNameSpecifierForFilterAtIndex(uint32_t index) {
141   LLDB_INSTRUMENT_VA(this, index);
142 
143   if (!IsValid())
144     return SBTypeNameSpecifier();
145   return SBTypeNameSpecifier(
146       m_opaque_sp->GetTypeNameSpecifierForFilterAtIndex(index));
147 }
148 
149 lldb::SBTypeNameSpecifier
150 SBTypeCategory::GetTypeNameSpecifierForFormatAtIndex(uint32_t index) {
151   LLDB_INSTRUMENT_VA(this, index);
152 
153   if (!IsValid())
154     return SBTypeNameSpecifier();
155   return SBTypeNameSpecifier(
156       m_opaque_sp->GetTypeNameSpecifierForFormatAtIndex(index));
157 }
158 
159 lldb::SBTypeNameSpecifier
160 SBTypeCategory::GetTypeNameSpecifierForSummaryAtIndex(uint32_t index) {
161   LLDB_INSTRUMENT_VA(this, index);
162 
163   if (!IsValid())
164     return SBTypeNameSpecifier();
165   return SBTypeNameSpecifier(
166       m_opaque_sp->GetTypeNameSpecifierForSummaryAtIndex(index));
167 }
168 
169 lldb::SBTypeNameSpecifier
170 SBTypeCategory::GetTypeNameSpecifierForSyntheticAtIndex(uint32_t index) {
171   LLDB_INSTRUMENT_VA(this, index);
172 
173   if (!IsValid())
174     return SBTypeNameSpecifier();
175   return SBTypeNameSpecifier(
176       m_opaque_sp->GetTypeNameSpecifierForSyntheticAtIndex(index));
177 }
178 
179 SBTypeFilter SBTypeCategory::GetFilterForType(SBTypeNameSpecifier spec) {
180   LLDB_INSTRUMENT_VA(this, spec);
181 
182   if (!IsValid())
183     return SBTypeFilter();
184 
185   if (!spec.IsValid())
186     return SBTypeFilter();
187 
188   lldb::TypeFilterImplSP children_sp;
189 
190   if (spec.IsRegex())
191     m_opaque_sp->GetRegexTypeFiltersContainer()->GetExact(
192         ConstString(spec.GetName()), children_sp);
193   else
194     m_opaque_sp->GetTypeFiltersContainer()->GetExact(
195         ConstString(spec.GetName()), children_sp);
196 
197   if (!children_sp)
198     return lldb::SBTypeFilter();
199 
200   TypeFilterImplSP filter_sp =
201       std::static_pointer_cast<TypeFilterImpl>(children_sp);
202 
203   return lldb::SBTypeFilter(filter_sp);
204 }
205 SBTypeFormat SBTypeCategory::GetFormatForType(SBTypeNameSpecifier spec) {
206   LLDB_INSTRUMENT_VA(this, spec);
207 
208   if (!IsValid())
209     return SBTypeFormat();
210 
211   if (!spec.IsValid())
212     return SBTypeFormat();
213 
214   lldb::TypeFormatImplSP format_sp;
215 
216   if (spec.IsRegex())
217     m_opaque_sp->GetRegexTypeFormatsContainer()->GetExact(
218         ConstString(spec.GetName()), format_sp);
219   else
220     m_opaque_sp->GetTypeFormatsContainer()->GetExact(
221         ConstString(spec.GetName()), format_sp);
222 
223   if (!format_sp)
224     return lldb::SBTypeFormat();
225 
226   return lldb::SBTypeFormat(format_sp);
227 }
228 
229 SBTypeSummary SBTypeCategory::GetSummaryForType(SBTypeNameSpecifier spec) {
230   LLDB_INSTRUMENT_VA(this, spec);
231 
232   if (!IsValid())
233     return SBTypeSummary();
234 
235   if (!spec.IsValid())
236     return SBTypeSummary();
237 
238   lldb::TypeSummaryImplSP summary_sp;
239 
240   if (spec.IsRegex())
241     m_opaque_sp->GetRegexTypeSummariesContainer()->GetExact(
242         ConstString(spec.GetName()), summary_sp);
243   else
244     m_opaque_sp->GetTypeSummariesContainer()->GetExact(
245         ConstString(spec.GetName()), summary_sp);
246 
247   if (!summary_sp)
248     return lldb::SBTypeSummary();
249 
250   return lldb::SBTypeSummary(summary_sp);
251 }
252 
253 SBTypeSynthetic SBTypeCategory::GetSyntheticForType(SBTypeNameSpecifier spec) {
254   LLDB_INSTRUMENT_VA(this, spec);
255 
256   if (!IsValid())
257     return SBTypeSynthetic();
258 
259   if (!spec.IsValid())
260     return SBTypeSynthetic();
261 
262   lldb::SyntheticChildrenSP children_sp;
263 
264   if (spec.IsRegex())
265     m_opaque_sp->GetRegexTypeSyntheticsContainer()->GetExact(
266         ConstString(spec.GetName()), children_sp);
267   else
268     m_opaque_sp->GetTypeSyntheticsContainer()->GetExact(
269         ConstString(spec.GetName()), children_sp);
270 
271   if (!children_sp)
272     return lldb::SBTypeSynthetic();
273 
274   ScriptedSyntheticChildrenSP synth_sp =
275       std::static_pointer_cast<ScriptedSyntheticChildren>(children_sp);
276 
277   return lldb::SBTypeSynthetic(synth_sp);
278 }
279 
280 SBTypeFilter SBTypeCategory::GetFilterAtIndex(uint32_t index) {
281   LLDB_INSTRUMENT_VA(this, index);
282 
283   if (!IsValid())
284     return SBTypeFilter();
285   lldb::SyntheticChildrenSP children_sp =
286       m_opaque_sp->GetSyntheticAtIndex((index));
287 
288   if (!children_sp.get())
289     return lldb::SBTypeFilter();
290 
291   TypeFilterImplSP filter_sp =
292       std::static_pointer_cast<TypeFilterImpl>(children_sp);
293 
294   return lldb::SBTypeFilter(filter_sp);
295 }
296 
297 SBTypeFormat SBTypeCategory::GetFormatAtIndex(uint32_t index) {
298   LLDB_INSTRUMENT_VA(this, index);
299 
300   if (!IsValid())
301     return SBTypeFormat();
302   return SBTypeFormat(m_opaque_sp->GetFormatAtIndex((index)));
303 }
304 
305 SBTypeSummary SBTypeCategory::GetSummaryAtIndex(uint32_t index) {
306   LLDB_INSTRUMENT_VA(this, index);
307 
308   if (!IsValid())
309     return SBTypeSummary();
310   return SBTypeSummary(m_opaque_sp->GetSummaryAtIndex((index)));
311 }
312 
313 SBTypeSynthetic SBTypeCategory::GetSyntheticAtIndex(uint32_t index) {
314   LLDB_INSTRUMENT_VA(this, index);
315 
316   if (!IsValid())
317     return SBTypeSynthetic();
318   lldb::SyntheticChildrenSP children_sp =
319       m_opaque_sp->GetSyntheticAtIndex((index));
320 
321   if (!children_sp.get())
322     return lldb::SBTypeSynthetic();
323 
324   ScriptedSyntheticChildrenSP synth_sp =
325       std::static_pointer_cast<ScriptedSyntheticChildren>(children_sp);
326 
327   return lldb::SBTypeSynthetic(synth_sp);
328 }
329 
330 bool SBTypeCategory::AddTypeFormat(SBTypeNameSpecifier type_name,
331                                    SBTypeFormat format) {
332   LLDB_INSTRUMENT_VA(this, type_name, format);
333 
334   if (!IsValid())
335     return false;
336 
337   if (!type_name.IsValid())
338     return false;
339 
340   if (!format.IsValid())
341     return false;
342 
343   if (type_name.IsRegex())
344     m_opaque_sp->GetRegexTypeFormatsContainer()->Add(
345         RegularExpression(type_name.GetName()), format.GetSP());
346   else
347     m_opaque_sp->GetTypeFormatsContainer()->Add(
348         ConstString(type_name.GetName()), format.GetSP());
349 
350   return true;
351 }
352 
353 bool SBTypeCategory::DeleteTypeFormat(SBTypeNameSpecifier type_name) {
354   LLDB_INSTRUMENT_VA(this, type_name);
355 
356   if (!IsValid())
357     return false;
358 
359   if (!type_name.IsValid())
360     return false;
361 
362   if (type_name.IsRegex())
363     return m_opaque_sp->GetRegexTypeFormatsContainer()->Delete(
364         ConstString(type_name.GetName()));
365   else
366     return m_opaque_sp->GetTypeFormatsContainer()->Delete(
367         ConstString(type_name.GetName()));
368 }
369 
370 bool SBTypeCategory::AddTypeSummary(SBTypeNameSpecifier type_name,
371                                     SBTypeSummary summary) {
372   LLDB_INSTRUMENT_VA(this, type_name, summary);
373 
374   if (!IsValid())
375     return false;
376 
377   if (!type_name.IsValid())
378     return false;
379 
380   if (!summary.IsValid())
381     return false;
382 
383   // FIXME: we need to iterate over all the Debugger objects and have each of
384   // them contain a copy of the function
385   // since we currently have formatters live in a global space, while Python
386   // code lives in a specific Debugger-related environment this should
387   // eventually be fixed by deciding a final location in the LLDB object space
388   // for formatters
389   if (summary.IsFunctionCode()) {
390     const void *name_token =
391         (const void *)ConstString(type_name.GetName()).GetCString();
392     const char *script = summary.GetData();
393     StringList input;
394     input.SplitIntoLines(script, strlen(script));
395     uint32_t num_debuggers = lldb_private::Debugger::GetNumDebuggers();
396     bool need_set = true;
397     for (uint32_t j = 0; j < num_debuggers; j++) {
398       DebuggerSP debugger_sp = lldb_private::Debugger::GetDebuggerAtIndex(j);
399       if (debugger_sp) {
400         ScriptInterpreter *interpreter_ptr =
401             debugger_sp->GetScriptInterpreter();
402         if (interpreter_ptr) {
403           std::string output;
404           if (interpreter_ptr->GenerateTypeScriptFunction(input, output,
405                                                           name_token) &&
406               !output.empty()) {
407             if (need_set) {
408               need_set = false;
409               summary.SetFunctionName(output.c_str());
410             }
411           }
412         }
413       }
414     }
415   }
416 
417   if (type_name.IsRegex())
418     m_opaque_sp->GetRegexTypeSummariesContainer()->Add(
419         RegularExpression(type_name.GetName()), summary.GetSP());
420   else
421     m_opaque_sp->GetTypeSummariesContainer()->Add(
422         ConstString(type_name.GetName()), summary.GetSP());
423 
424   return true;
425 }
426 
427 bool SBTypeCategory::DeleteTypeSummary(SBTypeNameSpecifier type_name) {
428   LLDB_INSTRUMENT_VA(this, type_name);
429 
430   if (!IsValid())
431     return false;
432 
433   if (!type_name.IsValid())
434     return false;
435 
436   if (type_name.IsRegex())
437     return m_opaque_sp->GetRegexTypeSummariesContainer()->Delete(
438         ConstString(type_name.GetName()));
439   else
440     return m_opaque_sp->GetTypeSummariesContainer()->Delete(
441         ConstString(type_name.GetName()));
442 }
443 
444 bool SBTypeCategory::AddTypeFilter(SBTypeNameSpecifier type_name,
445                                    SBTypeFilter filter) {
446   LLDB_INSTRUMENT_VA(this, type_name, filter);
447 
448   if (!IsValid())
449     return false;
450 
451   if (!type_name.IsValid())
452     return false;
453 
454   if (!filter.IsValid())
455     return false;
456 
457   if (type_name.IsRegex())
458     m_opaque_sp->GetRegexTypeFiltersContainer()->Add(
459         RegularExpression(type_name.GetName()), filter.GetSP());
460   else
461     m_opaque_sp->GetTypeFiltersContainer()->Add(
462         ConstString(type_name.GetName()), filter.GetSP());
463 
464   return true;
465 }
466 
467 bool SBTypeCategory::DeleteTypeFilter(SBTypeNameSpecifier type_name) {
468   LLDB_INSTRUMENT_VA(this, type_name);
469 
470   if (!IsValid())
471     return false;
472 
473   if (!type_name.IsValid())
474     return false;
475 
476   if (type_name.IsRegex())
477     return m_opaque_sp->GetRegexTypeFiltersContainer()->Delete(
478         ConstString(type_name.GetName()));
479   else
480     return m_opaque_sp->GetTypeFiltersContainer()->Delete(
481         ConstString(type_name.GetName()));
482 }
483 
484 bool SBTypeCategory::AddTypeSynthetic(SBTypeNameSpecifier type_name,
485                                       SBTypeSynthetic synth) {
486   LLDB_INSTRUMENT_VA(this, type_name, synth);
487 
488   if (!IsValid())
489     return false;
490 
491   if (!type_name.IsValid())
492     return false;
493 
494   if (!synth.IsValid())
495     return false;
496 
497   // FIXME: we need to iterate over all the Debugger objects and have each of
498   // them contain a copy of the function
499   // since we currently have formatters live in a global space, while Python
500   // code lives in a specific Debugger-related environment this should
501   // eventually be fixed by deciding a final location in the LLDB object space
502   // for formatters
503   if (synth.IsClassCode()) {
504     const void *name_token =
505         (const void *)ConstString(type_name.GetName()).GetCString();
506     const char *script = synth.GetData();
507     StringList input;
508     input.SplitIntoLines(script, strlen(script));
509     uint32_t num_debuggers = lldb_private::Debugger::GetNumDebuggers();
510     bool need_set = true;
511     for (uint32_t j = 0; j < num_debuggers; j++) {
512       DebuggerSP debugger_sp = lldb_private::Debugger::GetDebuggerAtIndex(j);
513       if (debugger_sp) {
514         ScriptInterpreter *interpreter_ptr =
515             debugger_sp->GetScriptInterpreter();
516         if (interpreter_ptr) {
517           std::string output;
518           if (interpreter_ptr->GenerateTypeSynthClass(input, output,
519                                                       name_token) &&
520               !output.empty()) {
521             if (need_set) {
522               need_set = false;
523               synth.SetClassName(output.c_str());
524             }
525           }
526         }
527       }
528     }
529   }
530 
531   if (type_name.IsRegex())
532     m_opaque_sp->GetRegexTypeSyntheticsContainer()->Add(
533         RegularExpression(type_name.GetName()), synth.GetSP());
534   else
535     m_opaque_sp->GetTypeSyntheticsContainer()->Add(
536         ConstString(type_name.GetName()), synth.GetSP());
537 
538   return true;
539 }
540 
541 bool SBTypeCategory::DeleteTypeSynthetic(SBTypeNameSpecifier type_name) {
542   LLDB_INSTRUMENT_VA(this, type_name);
543 
544   if (!IsValid())
545     return false;
546 
547   if (!type_name.IsValid())
548     return false;
549 
550   if (type_name.IsRegex())
551     return m_opaque_sp->GetRegexTypeSyntheticsContainer()->Delete(
552         ConstString(type_name.GetName()));
553   else
554     return m_opaque_sp->GetTypeSyntheticsContainer()->Delete(
555         ConstString(type_name.GetName()));
556 }
557 
558 bool SBTypeCategory::GetDescription(lldb::SBStream &description,
559                                     lldb::DescriptionLevel description_level) {
560   LLDB_INSTRUMENT_VA(this, description, description_level);
561 
562   if (!IsValid())
563     return false;
564   description.Printf("Category name: %s\n", GetName());
565   return true;
566 }
567 
568 lldb::SBTypeCategory &SBTypeCategory::
569 operator=(const lldb::SBTypeCategory &rhs) {
570   LLDB_INSTRUMENT_VA(this, rhs);
571 
572   if (this != &rhs) {
573     m_opaque_sp = rhs.m_opaque_sp;
574   }
575   return *this;
576 }
577 
578 bool SBTypeCategory::operator==(lldb::SBTypeCategory &rhs) {
579   LLDB_INSTRUMENT_VA(this, rhs);
580 
581   if (!IsValid())
582     return !rhs.IsValid();
583 
584   return m_opaque_sp.get() == rhs.m_opaque_sp.get();
585 }
586 
587 bool SBTypeCategory::operator!=(lldb::SBTypeCategory &rhs) {
588   LLDB_INSTRUMENT_VA(this, rhs);
589 
590   if (!IsValid())
591     return rhs.IsValid();
592 
593   return m_opaque_sp.get() != rhs.m_opaque_sp.get();
594 }
595 
596 lldb::TypeCategoryImplSP SBTypeCategory::GetSP() {
597   if (!IsValid())
598     return lldb::TypeCategoryImplSP();
599   return m_opaque_sp;
600 }
601 
602 void SBTypeCategory::SetSP(
603     const lldb::TypeCategoryImplSP &typecategory_impl_sp) {
604   m_opaque_sp = typecategory_impl_sp;
605 }
606 
607 SBTypeCategory::SBTypeCategory(
608     const lldb::TypeCategoryImplSP &typecategory_impl_sp)
609     : m_opaque_sp(typecategory_impl_sp) {}
610 
611 bool SBTypeCategory::IsDefaultCategory() {
612   if (!IsValid())
613     return false;
614 
615   return (strcmp(m_opaque_sp->GetName(), "default") == 0);
616 }
617