1 //===-- TypeSummary.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_TYPESUMMARY_H 10 #define LLDB_DATAFORMATTERS_TYPESUMMARY_H 11 12 #include <cstdint> 13 14 #include <functional> 15 #include <memory> 16 #include <string> 17 18 #include "lldb/lldb-enumerations.h" 19 #include "lldb/lldb-public.h" 20 21 #include "lldb/Core/FormatEntity.h" 22 #include "lldb/Utility/Status.h" 23 #include "lldb/Utility/StructuredData.h" 24 25 namespace llvm { 26 class MemoryBuffer; 27 } 28 29 namespace lldb_private { 30 class TypeSummaryOptions { 31 public: 32 TypeSummaryOptions(); 33 34 ~TypeSummaryOptions() = default; 35 36 lldb::LanguageType GetLanguage() const; 37 38 lldb::TypeSummaryCapping GetCapping() const; 39 40 TypeSummaryOptions &SetLanguage(lldb::LanguageType); 41 42 TypeSummaryOptions &SetCapping(lldb::TypeSummaryCapping); 43 44 private: 45 lldb::LanguageType m_lang = lldb::eLanguageTypeUnknown; 46 lldb::TypeSummaryCapping m_capping = lldb::eTypeSummaryCapped; 47 }; 48 49 class TypeSummaryImpl { 50 public: 51 enum class Kind { eSummaryString, eScript, eBytecode, eCallback, eInternal }; 52 53 virtual ~TypeSummaryImpl() = default; 54 GetKind()55 Kind GetKind() const { return m_kind; } 56 57 class Flags { 58 public: 59 Flags() = default; 60 Flags(const Flags & other)61 Flags(const Flags &other) : m_flags(other.m_flags) {} 62 Flags(uint32_t value)63 Flags(uint32_t value) : m_flags(value) {} 64 65 Flags &operator=(const Flags &rhs) { 66 if (&rhs != this) 67 m_flags = rhs.m_flags; 68 69 return *this; 70 } 71 72 Flags &operator=(const uint32_t &rhs) { 73 m_flags = rhs; 74 return *this; 75 } 76 Clear()77 Flags &Clear() { 78 m_flags = 0; 79 return *this; 80 } 81 GetCascades()82 bool GetCascades() const { 83 return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade; 84 } 85 86 Flags &SetCascades(bool value = true) { 87 if (value) 88 m_flags |= lldb::eTypeOptionCascade; 89 else 90 m_flags &= ~lldb::eTypeOptionCascade; 91 return *this; 92 } 93 GetSkipPointers()94 bool GetSkipPointers() const { 95 return (m_flags & lldb::eTypeOptionSkipPointers) == 96 lldb::eTypeOptionSkipPointers; 97 } 98 99 Flags &SetSkipPointers(bool value = true) { 100 if (value) 101 m_flags |= lldb::eTypeOptionSkipPointers; 102 else 103 m_flags &= ~lldb::eTypeOptionSkipPointers; 104 return *this; 105 } 106 GetSkipReferences()107 bool GetSkipReferences() const { 108 return (m_flags & lldb::eTypeOptionSkipReferences) == 109 lldb::eTypeOptionSkipReferences; 110 } 111 112 Flags &SetSkipReferences(bool value = true) { 113 if (value) 114 m_flags |= lldb::eTypeOptionSkipReferences; 115 else 116 m_flags &= ~lldb::eTypeOptionSkipReferences; 117 return *this; 118 } 119 GetDontShowChildren()120 bool GetDontShowChildren() const { 121 return (m_flags & lldb::eTypeOptionHideChildren) == 122 lldb::eTypeOptionHideChildren; 123 } 124 125 Flags &SetDontShowChildren(bool value = true) { 126 if (value) 127 m_flags |= lldb::eTypeOptionHideChildren; 128 else 129 m_flags &= ~lldb::eTypeOptionHideChildren; 130 return *this; 131 } 132 GetHideEmptyAggregates()133 bool GetHideEmptyAggregates() const { 134 return (m_flags & lldb::eTypeOptionHideEmptyAggregates) == 135 lldb::eTypeOptionHideEmptyAggregates; 136 } 137 138 Flags &SetHideEmptyAggregates(bool value = true) { 139 if (value) 140 m_flags |= lldb::eTypeOptionHideEmptyAggregates; 141 else 142 m_flags &= ~lldb::eTypeOptionHideEmptyAggregates; 143 return *this; 144 } 145 GetDontShowValue()146 bool GetDontShowValue() const { 147 return (m_flags & lldb::eTypeOptionHideValue) == 148 lldb::eTypeOptionHideValue; 149 } 150 151 Flags &SetDontShowValue(bool value = true) { 152 if (value) 153 m_flags |= lldb::eTypeOptionHideValue; 154 else 155 m_flags &= ~lldb::eTypeOptionHideValue; 156 return *this; 157 } 158 GetShowMembersOneLiner()159 bool GetShowMembersOneLiner() const { 160 return (m_flags & lldb::eTypeOptionShowOneLiner) == 161 lldb::eTypeOptionShowOneLiner; 162 } 163 164 Flags &SetShowMembersOneLiner(bool value = true) { 165 if (value) 166 m_flags |= lldb::eTypeOptionShowOneLiner; 167 else 168 m_flags &= ~lldb::eTypeOptionShowOneLiner; 169 return *this; 170 } 171 GetHideItemNames()172 bool GetHideItemNames() const { 173 return (m_flags & lldb::eTypeOptionHideNames) == 174 lldb::eTypeOptionHideNames; 175 } 176 177 Flags &SetHideItemNames(bool value = true) { 178 if (value) 179 m_flags |= lldb::eTypeOptionHideNames; 180 else 181 m_flags &= ~lldb::eTypeOptionHideNames; 182 return *this; 183 } 184 GetNonCacheable()185 bool GetNonCacheable() const { 186 return (m_flags & lldb::eTypeOptionNonCacheable) == 187 lldb::eTypeOptionNonCacheable; 188 } 189 190 Flags &SetNonCacheable(bool value = true) { 191 if (value) 192 m_flags |= lldb::eTypeOptionNonCacheable; 193 else 194 m_flags &= ~lldb::eTypeOptionNonCacheable; 195 return *this; 196 } 197 GetValue()198 uint32_t GetValue() { return m_flags; } 199 SetValue(uint32_t value)200 void SetValue(uint32_t value) { m_flags = value; } 201 202 private: 203 uint32_t m_flags = lldb::eTypeOptionCascade; 204 }; 205 Cascades()206 bool Cascades() const { return m_flags.GetCascades(); } 207 SkipsPointers()208 bool SkipsPointers() const { return m_flags.GetSkipPointers(); } 209 SkipsReferences()210 bool SkipsReferences() const { return m_flags.GetSkipReferences(); } 211 NonCacheable()212 bool NonCacheable() const { return m_flags.GetNonCacheable(); } 213 DoesPrintChildren(ValueObject * valobj)214 virtual bool DoesPrintChildren(ValueObject *valobj) const { 215 return !m_flags.GetDontShowChildren(); 216 } 217 DoesPrintEmptyAggregates()218 virtual bool DoesPrintEmptyAggregates() const { 219 return !m_flags.GetHideEmptyAggregates(); 220 } 221 DoesPrintValue(ValueObject * valobj)222 virtual bool DoesPrintValue(ValueObject *valobj) const { 223 return !m_flags.GetDontShowValue(); 224 } 225 IsOneLiner()226 bool IsOneLiner() const { return m_flags.GetShowMembersOneLiner(); } 227 HideNames(ValueObject * valobj)228 virtual bool HideNames(ValueObject *valobj) const { 229 return m_flags.GetHideItemNames(); 230 } 231 SetCascades(bool value)232 void SetCascades(bool value) { m_flags.SetCascades(value); } 233 SetSkipsPointers(bool value)234 void SetSkipsPointers(bool value) { m_flags.SetSkipPointers(value); } 235 SetSkipsReferences(bool value)236 void SetSkipsReferences(bool value) { m_flags.SetSkipReferences(value); } 237 SetDoesPrintChildren(bool value)238 virtual void SetDoesPrintChildren(bool value) { 239 m_flags.SetDontShowChildren(!value); 240 } 241 SetDoesPrintValue(bool value)242 virtual void SetDoesPrintValue(bool value) { 243 m_flags.SetDontShowValue(!value); 244 } 245 SetIsOneLiner(bool value)246 void SetIsOneLiner(bool value) { m_flags.SetShowMembersOneLiner(value); } 247 SetHideNames(bool value)248 virtual void SetHideNames(bool value) { m_flags.SetHideItemNames(value); } 249 SetNonCacheable(bool value)250 virtual void SetNonCacheable(bool value) { m_flags.SetNonCacheable(value); } 251 GetOptions()252 uint32_t GetOptions() { return m_flags.GetValue(); } 253 SetOptions(uint32_t value)254 void SetOptions(uint32_t value) { m_flags.SetValue(value); } 255 GetPtrMatchDepth()256 uint32_t GetPtrMatchDepth() { return m_ptr_match_depth; } 257 SetPtrMatchDepth(uint32_t value)258 void SetPtrMatchDepth(uint32_t value) { m_ptr_match_depth = value; } 259 260 // we are using a ValueObject* instead of a ValueObjectSP because we do not 261 // need to hold on to this for extended periods of time and we trust the 262 // ValueObject to stay around for as long as it is required for us to 263 // generate its summary 264 virtual bool FormatObject(ValueObject *valobj, std::string &dest, 265 const TypeSummaryOptions &options) = 0; 266 267 virtual std::string GetDescription() = 0; 268 269 /// Get the name of the Type Summary Provider, either a C++ class, a summary 270 /// string, or a script function name. 271 virtual std::string GetName() = 0; 272 273 /// Get the name of the kind of Summary Provider, either c++, summary string, 274 /// script or python. 275 virtual std::string GetSummaryKindName(); 276 GetRevision()277 uint32_t &GetRevision() { return m_my_revision; } 278 279 typedef std::shared_ptr<TypeSummaryImpl> SharedPointer; 280 281 protected: 282 uint32_t m_my_revision = 0; 283 Flags m_flags; 284 285 TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags, 286 uint32_t ptr_match_depth = 1); 287 288 private: 289 Kind m_kind; 290 uint32_t m_ptr_match_depth = 1; 291 TypeSummaryImpl(const TypeSummaryImpl &) = delete; 292 const TypeSummaryImpl &operator=(const TypeSummaryImpl &) = delete; 293 }; 294 295 // simple string-based summaries, using ${var to show data 296 struct StringSummaryFormat : public TypeSummaryImpl { 297 std::string m_format_str; 298 FormatEntity::Entry m_format; 299 Status m_error; 300 301 StringSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *f, 302 uint32_t ptr_match_depth = 1); 303 304 ~StringSummaryFormat() override = default; 305 GetSummaryStringStringSummaryFormat306 const char *GetSummaryString() const { return m_format_str.c_str(); } 307 308 void SetSummaryString(const char *f); 309 310 bool FormatObject(ValueObject *valobj, std::string &dest, 311 const TypeSummaryOptions &options) override; 312 313 std::string GetDescription() override; 314 315 std::string GetName() override; 316 classofStringSummaryFormat317 static bool classof(const TypeSummaryImpl *S) { 318 return S->GetKind() == Kind::eSummaryString; 319 } 320 321 private: 322 StringSummaryFormat(const StringSummaryFormat &) = delete; 323 const StringSummaryFormat &operator=(const StringSummaryFormat &) = delete; 324 }; 325 326 // summaries implemented via a C++ function 327 struct CXXFunctionSummaryFormat : public TypeSummaryImpl { 328 // we should convert these to SBValue and SBStream if we ever cross the 329 // boundary towards the external world 330 typedef std::function<bool(ValueObject &, Stream &, 331 const TypeSummaryOptions &)> 332 Callback; 333 334 Callback m_impl; 335 std::string m_description; 336 337 CXXFunctionSummaryFormat(const TypeSummaryImpl::Flags &flags, Callback impl, 338 const char *description, 339 uint32_t ptr_match_depth = 1); 340 341 ~CXXFunctionSummaryFormat() override = default; 342 GetBackendFunctionCXXFunctionSummaryFormat343 Callback GetBackendFunction() const { return m_impl; } 344 GetTextualInfoCXXFunctionSummaryFormat345 const char *GetTextualInfo() const { return m_description.c_str(); } 346 SetBackendFunctionCXXFunctionSummaryFormat347 void SetBackendFunction(Callback cb_func) { m_impl = std::move(cb_func); } 348 SetTextualInfoCXXFunctionSummaryFormat349 void SetTextualInfo(const char *descr) { 350 if (descr) 351 m_description.assign(descr); 352 else 353 m_description.clear(); 354 } 355 356 bool FormatObject(ValueObject *valobj, std::string &dest, 357 const TypeSummaryOptions &options) override; 358 359 std::string GetDescription() override; 360 classofCXXFunctionSummaryFormat361 static bool classof(const TypeSummaryImpl *S) { 362 return S->GetKind() == Kind::eCallback; 363 } 364 365 std::string GetName() override; 366 367 typedef std::shared_ptr<CXXFunctionSummaryFormat> SharedPointer; 368 369 private: 370 CXXFunctionSummaryFormat(const CXXFunctionSummaryFormat &) = delete; 371 const CXXFunctionSummaryFormat & 372 operator=(const CXXFunctionSummaryFormat &) = delete; 373 }; 374 375 // Python-based summaries, running script code to show data 376 struct ScriptSummaryFormat : public TypeSummaryImpl { 377 std::string m_function_name; 378 std::string m_python_script; 379 std::string m_script_formatter_name; 380 StructuredData::ObjectSP m_script_function_sp; 381 382 ScriptSummaryFormat(const TypeSummaryImpl::Flags &flags, 383 const char *function_name, 384 const char *python_script = nullptr, 385 uint32_t ptr_match_depth = 1); 386 387 ~ScriptSummaryFormat() override = default; 388 GetFunctionNameScriptSummaryFormat389 const char *GetFunctionName() const { return m_function_name.c_str(); } 390 GetPythonScriptScriptSummaryFormat391 const char *GetPythonScript() const { return m_python_script.c_str(); } 392 SetFunctionNameScriptSummaryFormat393 void SetFunctionName(const char *function_name) { 394 if (function_name) 395 m_function_name.assign(function_name); 396 else 397 m_function_name.clear(); 398 m_python_script.clear(); 399 } 400 SetPythonScriptScriptSummaryFormat401 void SetPythonScript(const char *script) { 402 if (script) 403 m_python_script.assign(script); 404 else 405 m_python_script.clear(); 406 } 407 408 bool FormatObject(ValueObject *valobj, std::string &dest, 409 const TypeSummaryOptions &options) override; 410 411 std::string GetDescription() override; 412 413 std::string GetName() override; 414 classofScriptSummaryFormat415 static bool classof(const TypeSummaryImpl *S) { 416 return S->GetKind() == Kind::eScript; 417 } 418 419 typedef std::shared_ptr<ScriptSummaryFormat> SharedPointer; 420 421 private: 422 ScriptSummaryFormat(const ScriptSummaryFormat &) = delete; 423 const ScriptSummaryFormat &operator=(const ScriptSummaryFormat &) = delete; 424 }; 425 426 /// A summary formatter that is defined in LLDB formmater bytecode. 427 class BytecodeSummaryFormat : public TypeSummaryImpl { 428 std::unique_ptr<llvm::MemoryBuffer> m_bytecode; 429 430 public: 431 BytecodeSummaryFormat(const TypeSummaryImpl::Flags &flags, 432 std::unique_ptr<llvm::MemoryBuffer> bytecode); 433 bool FormatObject(ValueObject *valobj, std::string &dest, 434 const TypeSummaryOptions &options) override; 435 std::string GetDescription() override; 436 std::string GetName() override; classof(const TypeSummaryImpl * S)437 static bool classof(const TypeSummaryImpl *S) { 438 return S->GetKind() == Kind::eBytecode; 439 } 440 }; 441 442 } // namespace lldb_private 443 444 #endif // LLDB_DATAFORMATTERS_TYPESUMMARY_H 445