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