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