xref: /freebsd/contrib/llvm-project/lldb/include/lldb/DataFormatters/TypeSynthetic.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- TypeSynthetic.h -----------------------------------------*- C++ -*-===//
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 #ifndef LLDB_DATAFORMATTERS_TYPESYNTHETIC_H
10 #define LLDB_DATAFORMATTERS_TYPESYNTHETIC_H
11 
12 #include <cstdint>
13 
14 #include <functional>
15 #include <initializer_list>
16 #include <memory>
17 #include <string>
18 #include <vector>
19 
20 #include "lldb/lldb-enumerations.h"
21 #include "lldb/lldb-public.h"
22 
23 #include "lldb/Utility/StructuredData.h"
24 #include "lldb/ValueObject/ValueObject.h"
25 
26 namespace lldb_private {
27 class SyntheticChildrenFrontEnd {
28 protected:
29   ValueObject &m_backend;
30 
SetValid(bool valid)31   void SetValid(bool valid) { m_valid = valid; }
32 
IsValid()33   bool IsValid() { return m_valid; }
34 
35 public:
SyntheticChildrenFrontEnd(ValueObject & backend)36   SyntheticChildrenFrontEnd(ValueObject &backend)
37       : m_backend(backend), m_valid(true) {}
38 
39   virtual ~SyntheticChildrenFrontEnd() = default;
40 
41   virtual llvm::Expected<uint32_t> CalculateNumChildren() = 0;
42 
CalculateNumChildren(uint32_t max)43   virtual llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) {
44     auto count = CalculateNumChildren();
45     if (!count)
46       return count;
47     return *count <= max ? *count : max;
48   }
49 
50   uint32_t CalculateNumChildrenIgnoringErrors(uint32_t max = UINT32_MAX);
51 
52   virtual lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) = 0;
53 
54   virtual llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) = 0;
55 
56   /// This function is assumed to always succeed and if it fails, the front-end
57   /// should know to deal with it in the correct way (most probably, by refusing
58   /// to return any children). The return value of \ref Update should actually
59   /// be interpreted as "ValueObjectSynthetic cache is good/bad". If this
60   /// function returns \ref lldb::ChildCacheState::eReuse, \ref
61   /// ValueObjectSynthetic is allowed to use the children it fetched
62   /// previously and cached. Otherwise, \ref ValueObjectSynthetic must
63   /// throw away its cache, and query again for children.
64   virtual lldb::ChildCacheState Update() = 0;
65 
66   // if this function returns false, then CalculateNumChildren() MUST return 0
67   // since UI frontends might validly decide not to inquire for children given
68   // a false return value from this call if it returns true, then
69   // CalculateNumChildren() can return any number >= 0 (0 being valid) it
70   // should if at all possible be more efficient than CalculateNumChildren()
MightHaveChildren()71   virtual bool MightHaveChildren() { return true; }
72 
73   // if this function returns a non-null ValueObject, then the returned
74   // ValueObject will stand for this ValueObject whenever a "value" request is
75   // made to this ValueObject
GetSyntheticValue()76   virtual lldb::ValueObjectSP GetSyntheticValue() { return nullptr; }
77 
78   // if this function returns a non-empty ConstString, then clients are
79   // expected to use the return as the name of the type of this ValueObject for
80   // display purposes
GetSyntheticTypeName()81   virtual ConstString GetSyntheticTypeName() { return ConstString(); }
82 
83   typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer;
84   typedef std::unique_ptr<SyntheticChildrenFrontEnd> AutoPointer;
85 
86 protected:
87   lldb::ValueObjectSP
88   CreateValueObjectFromExpression(llvm::StringRef name,
89                                   llvm::StringRef expression,
90                                   const ExecutionContext &exe_ctx);
91 
92   lldb::ValueObjectSP
93   CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address,
94                                const ExecutionContext &exe_ctx,
95                                CompilerType type, bool do_deref = true);
96 
97   lldb::ValueObjectSP CreateValueObjectFromData(llvm::StringRef name,
98                                                 const DataExtractor &data,
99                                                 const ExecutionContext &exe_ctx,
100                                                 CompilerType type);
101 
102 private:
103   bool m_valid;
104   SyntheticChildrenFrontEnd(const SyntheticChildrenFrontEnd &) = delete;
105   const SyntheticChildrenFrontEnd &
106   operator=(const SyntheticChildrenFrontEnd &) = delete;
107 };
108 
109 class SyntheticValueProviderFrontEnd : public SyntheticChildrenFrontEnd {
110 public:
SyntheticValueProviderFrontEnd(ValueObject & backend)111   SyntheticValueProviderFrontEnd(ValueObject &backend)
112       : SyntheticChildrenFrontEnd(backend) {}
113 
114   ~SyntheticValueProviderFrontEnd() override = default;
115 
CalculateNumChildren()116   llvm::Expected<uint32_t> CalculateNumChildren() override { return 0; }
117 
GetChildAtIndex(uint32_t idx)118   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { return nullptr; }
119 
GetIndexOfChildWithName(ConstString name)120   llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
121     return llvm::createStringError("Type has no child named '%s'",
122                                    name.AsCString());
123   }
124 
Update()125   lldb::ChildCacheState Update() override {
126     return lldb::ChildCacheState::eRefetch;
127   }
128 
MightHaveChildren()129   bool MightHaveChildren() override { return false; }
130 
131   lldb::ValueObjectSP GetSyntheticValue() override = 0;
132 
133 private:
134   SyntheticValueProviderFrontEnd(const SyntheticValueProviderFrontEnd &) =
135       delete;
136   const SyntheticValueProviderFrontEnd &
137   operator=(const SyntheticValueProviderFrontEnd &) = delete;
138 };
139 
140 class SyntheticChildren {
141 public:
142   class Flags {
143   public:
144     Flags() = default;
145 
Flags(const Flags & other)146     Flags(const Flags &other) : m_flags(other.m_flags) {}
147 
Flags(uint32_t value)148     Flags(uint32_t value) : m_flags(value) {}
149 
150     Flags &operator=(const Flags &rhs) {
151       if (&rhs != this)
152         m_flags = rhs.m_flags;
153 
154       return *this;
155     }
156 
157     Flags &operator=(const uint32_t &rhs) {
158       m_flags = rhs;
159       return *this;
160     }
161 
Clear()162     Flags &Clear() {
163       m_flags = 0;
164       return *this;
165     }
166 
GetCascades()167     bool GetCascades() const {
168       return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade;
169     }
170 
171     Flags &SetCascades(bool value = true) {
172       if (value)
173         m_flags |= lldb::eTypeOptionCascade;
174       else
175         m_flags &= ~lldb::eTypeOptionCascade;
176       return *this;
177     }
178 
GetSkipPointers()179     bool GetSkipPointers() const {
180       return (m_flags & lldb::eTypeOptionSkipPointers) ==
181              lldb::eTypeOptionSkipPointers;
182     }
183 
184     Flags &SetSkipPointers(bool value = true) {
185       if (value)
186         m_flags |= lldb::eTypeOptionSkipPointers;
187       else
188         m_flags &= ~lldb::eTypeOptionSkipPointers;
189       return *this;
190     }
191 
GetSkipReferences()192     bool GetSkipReferences() const {
193       return (m_flags & lldb::eTypeOptionSkipReferences) ==
194              lldb::eTypeOptionSkipReferences;
195     }
196 
197     Flags &SetSkipReferences(bool value = true) {
198       if (value)
199         m_flags |= lldb::eTypeOptionSkipReferences;
200       else
201         m_flags &= ~lldb::eTypeOptionSkipReferences;
202       return *this;
203     }
204 
GetNonCacheable()205     bool GetNonCacheable() const {
206       return (m_flags & lldb::eTypeOptionNonCacheable) ==
207              lldb::eTypeOptionNonCacheable;
208     }
209 
210     Flags &SetNonCacheable(bool value = true) {
211       if (value)
212         m_flags |= lldb::eTypeOptionNonCacheable;
213       else
214         m_flags &= ~lldb::eTypeOptionNonCacheable;
215       return *this;
216     }
217 
GetFrontEndWantsDereference()218     bool GetFrontEndWantsDereference() const {
219       return (m_flags & lldb::eTypeOptionFrontEndWantsDereference) ==
220              lldb::eTypeOptionFrontEndWantsDereference;
221     }
222 
223     Flags &SetFrontEndWantsDereference(bool value = true) {
224       if (value)
225         m_flags |= lldb::eTypeOptionFrontEndWantsDereference;
226       else
227         m_flags &= ~lldb::eTypeOptionFrontEndWantsDereference;
228       return *this;
229     }
230 
GetValue()231     uint32_t GetValue() { return m_flags; }
232 
SetValue(uint32_t value)233     void SetValue(uint32_t value) { m_flags = value; }
234 
235   private:
236     uint32_t m_flags = lldb::eTypeOptionCascade;
237   };
238 
239   SyntheticChildren(const Flags &flags);
240 
241   virtual ~SyntheticChildren();
242 
Cascades()243   bool Cascades() const { return m_flags.GetCascades(); }
244 
SkipsPointers()245   bool SkipsPointers() const { return m_flags.GetSkipPointers(); }
246 
SkipsReferences()247   bool SkipsReferences() const { return m_flags.GetSkipReferences(); }
248 
NonCacheable()249   bool NonCacheable() const { return m_flags.GetNonCacheable(); }
250 
WantsDereference()251   bool WantsDereference() const { return m_flags.GetFrontEndWantsDereference();}
252 
SetCascades(bool value)253   void SetCascades(bool value) { m_flags.SetCascades(value); }
254 
SetSkipsPointers(bool value)255   void SetSkipsPointers(bool value) { m_flags.SetSkipPointers(value); }
256 
SetSkipsReferences(bool value)257   void SetSkipsReferences(bool value) { m_flags.SetSkipReferences(value); }
258 
SetNonCacheable(bool value)259   void SetNonCacheable(bool value) { m_flags.SetNonCacheable(value); }
260 
GetOptions()261   uint32_t GetOptions() { return m_flags.GetValue(); }
262 
SetOptions(uint32_t value)263   void SetOptions(uint32_t value) { m_flags.SetValue(value); }
264 
265   virtual bool IsScripted() = 0;
266 
267   virtual std::string GetDescription() = 0;
268 
269   virtual SyntheticChildrenFrontEnd::AutoPointer
270   GetFrontEnd(ValueObject &backend) = 0;
271 
272   typedef std::shared_ptr<SyntheticChildren> SharedPointer;
273 
GetRevision()274   uint32_t &GetRevision() { return m_my_revision; }
275 
GetPtrMatchDepth()276   uint32_t GetPtrMatchDepth() { return m_ptr_match_depth; }
277 
SetPtrMatchDepth(uint32_t value)278   void SetPtrMatchDepth(uint32_t value) { m_ptr_match_depth = value; }
279 
280 protected:
281   uint32_t m_my_revision = 0;
282   Flags m_flags;
283   uint32_t m_ptr_match_depth = 1;
284 
285 private:
286   SyntheticChildren(const SyntheticChildren &) = delete;
287   const SyntheticChildren &operator=(const SyntheticChildren &) = delete;
288 };
289 
290 class TypeFilterImpl : public SyntheticChildren {
291   std::vector<std::string> m_expression_paths;
292 
293 public:
TypeFilterImpl(const SyntheticChildren::Flags & flags)294   TypeFilterImpl(const SyntheticChildren::Flags &flags)
295       : SyntheticChildren(flags) {}
296 
TypeFilterImpl(const SyntheticChildren::Flags & flags,const std::initializer_list<const char * > items)297   TypeFilterImpl(const SyntheticChildren::Flags &flags,
298                  const std::initializer_list<const char *> items)
299       : SyntheticChildren(flags) {
300     for (auto path : items)
301       AddExpressionPath(path);
302   }
303 
AddExpressionPath(const char * path)304   void AddExpressionPath(const char *path) {
305     AddExpressionPath(std::string(path));
306   }
307 
Clear()308   void Clear() { m_expression_paths.clear(); }
309 
GetCount()310   size_t GetCount() const { return m_expression_paths.size(); }
311 
GetExpressionPathAtIndex(size_t i)312   const char *GetExpressionPathAtIndex(size_t i) const {
313     return m_expression_paths[i].c_str();
314   }
315 
SetExpressionPathAtIndex(size_t i,const char * path)316   bool SetExpressionPathAtIndex(size_t i, const char *path) {
317     return SetExpressionPathAtIndex(i, std::string(path));
318   }
319 
320   void AddExpressionPath(const std::string &path);
321 
322   bool SetExpressionPathAtIndex(size_t i, const std::string &path);
323 
IsScripted()324   bool IsScripted() override { return false; }
325 
326   std::string GetDescription() override;
327 
328   class FrontEnd : public SyntheticChildrenFrontEnd {
329   public:
FrontEnd(TypeFilterImpl * flt,ValueObject & backend)330     FrontEnd(TypeFilterImpl *flt, ValueObject &backend)
331         : SyntheticChildrenFrontEnd(backend), filter(flt) {}
332 
333     ~FrontEnd() override = default;
334 
CalculateNumChildren()335     llvm::Expected<uint32_t> CalculateNumChildren() override {
336       return filter->GetCount();
337     }
338 
GetChildAtIndex(uint32_t idx)339     lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
340       if (idx >= filter->GetCount())
341         return lldb::ValueObjectSP();
342       return m_backend.GetSyntheticExpressionPathChild(
343           filter->GetExpressionPathAtIndex(idx), true);
344     }
345 
Update()346     lldb::ChildCacheState Update() override {
347       return lldb::ChildCacheState::eRefetch;
348     }
349 
MightHaveChildren()350     bool MightHaveChildren() override { return filter->GetCount() > 0; }
351 
352     llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
353 
354     typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer;
355 
356   private:
357     TypeFilterImpl *filter;
358 
359     FrontEnd(const FrontEnd &) = delete;
360     const FrontEnd &operator=(const FrontEnd &) = delete;
361   };
362 
363   SyntheticChildrenFrontEnd::AutoPointer
GetFrontEnd(ValueObject & backend)364   GetFrontEnd(ValueObject &backend) override {
365     return SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(this, backend));
366   }
367 
368   typedef std::shared_ptr<TypeFilterImpl> SharedPointer;
369 
370 private:
371   TypeFilterImpl(const TypeFilterImpl &) = delete;
372   const TypeFilterImpl &operator=(const TypeFilterImpl &) = delete;
373 };
374 
375 class CXXSyntheticChildren : public SyntheticChildren {
376 public:
377   typedef std::function<SyntheticChildrenFrontEnd *(CXXSyntheticChildren *,
378                                                     lldb::ValueObjectSP)>
379       CreateFrontEndCallback;
380   CXXSyntheticChildren(const SyntheticChildren::Flags &flags,
381                        const char *description, CreateFrontEndCallback callback);
382 
383   virtual ~CXXSyntheticChildren();
384 
IsScripted()385   bool IsScripted() override { return false; }
386 
387   std::string GetDescription() override;
388 
389   SyntheticChildrenFrontEnd::AutoPointer
GetFrontEnd(ValueObject & backend)390   GetFrontEnd(ValueObject &backend) override {
391     return SyntheticChildrenFrontEnd::AutoPointer(
392         m_create_callback(this, backend.GetSP()));
393   }
394 
395 protected:
396   CreateFrontEndCallback m_create_callback;
397   std::string m_description;
398 
399 private:
400   CXXSyntheticChildren(const CXXSyntheticChildren &) = delete;
401   const CXXSyntheticChildren &operator=(const CXXSyntheticChildren &) = delete;
402 };
403 
404 class ScriptedSyntheticChildren : public SyntheticChildren {
405   std::string m_python_class;
406   std::string m_python_code;
407 
408 public:
409   ScriptedSyntheticChildren(const SyntheticChildren::Flags &flags,
410                             const char *pclass, const char *pcode = nullptr)
SyntheticChildren(flags)411       : SyntheticChildren(flags) {
412     if (pclass)
413       m_python_class = pclass;
414     if (pcode)
415       m_python_code = pcode;
416   }
417 
GetPythonClassName()418   const char *GetPythonClassName() { return m_python_class.c_str(); }
419 
GetPythonCode()420   const char *GetPythonCode() { return m_python_code.c_str(); }
421 
SetPythonClassName(const char * fname)422   void SetPythonClassName(const char *fname) {
423     m_python_class.assign(fname);
424     m_python_code.clear();
425   }
426 
SetPythonCode(const char * script)427   void SetPythonCode(const char *script) { m_python_code.assign(script); }
428 
429   std::string GetDescription() override;
430 
IsScripted()431   bool IsScripted() override { return true; }
432 
433   class FrontEnd : public SyntheticChildrenFrontEnd {
434   public:
435     FrontEnd(std::string pclass, ValueObject &backend);
436 
437     ~FrontEnd() override;
438 
439     bool IsValid();
440 
441     llvm::Expected<uint32_t> CalculateNumChildren() override;
442 
443     llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override;
444 
445     lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
446 
447     lldb::ChildCacheState Update() override;
448 
449     bool MightHaveChildren() override;
450 
451     llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
452 
453     lldb::ValueObjectSP GetSyntheticValue() override;
454 
455     ConstString GetSyntheticTypeName() override;
456 
457     typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer;
458 
459   private:
460     std::string m_python_class;
461     StructuredData::ObjectSP m_wrapper_sp;
462     ScriptInterpreter *m_interpreter;
463 
464     FrontEnd(const FrontEnd &) = delete;
465     const FrontEnd &operator=(const FrontEnd &) = delete;
466   };
467 
468   SyntheticChildrenFrontEnd::AutoPointer
GetFrontEnd(ValueObject & backend)469   GetFrontEnd(ValueObject &backend) override {
470     auto synth_ptr = SyntheticChildrenFrontEnd::AutoPointer(
471         new FrontEnd(m_python_class, backend));
472     if (synth_ptr && ((FrontEnd *)synth_ptr.get())->IsValid())
473       return synth_ptr;
474     return nullptr;
475   }
476 
477 private:
478   ScriptedSyntheticChildren(const ScriptedSyntheticChildren &) = delete;
479   const ScriptedSyntheticChildren &
480   operator=(const ScriptedSyntheticChildren &) = delete;
481 };
482 } // namespace lldb_private
483 
484 #endif // LLDB_DATAFORMATTERS_TYPESYNTHETIC_H
485