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