1 //===-- StructuredData.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_UTILITY_STRUCTUREDDATA_H 10 #define LLDB_UTILITY_STRUCTUREDDATA_H 11 12 #include "llvm/ADT/StringMap.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/Support/JSON.h" 15 16 #include "lldb/Utility/FileSpec.h" 17 #include "lldb/Utility/Stream.h" 18 #include "lldb/lldb-enumerations.h" 19 20 #include <cassert> 21 #include <cstddef> 22 #include <cstdint> 23 #include <functional> 24 #include <map> 25 #include <memory> 26 #include <optional> 27 #include <string> 28 #include <type_traits> 29 #include <utility> 30 #include <variant> 31 #include <vector> 32 33 namespace lldb_private { 34 class Status; 35 } 36 37 namespace lldb_private { 38 39 /// \class StructuredData StructuredData.h "lldb/Utility/StructuredData.h" 40 /// A class which can hold structured data 41 /// 42 /// The StructuredData class is designed to hold the data from a JSON or plist 43 /// style file -- a serialized data structure with dictionaries (maps, 44 /// hashes), arrays, and concrete values like integers, floating point 45 /// numbers, strings, booleans. 46 /// 47 /// StructuredData does not presuppose any knowledge of the schema for the 48 /// data it is holding; it can parse JSON data, for instance, and other parts 49 /// of lldb can iterate through the parsed data set to find keys and values 50 /// that may be present. 51 52 class StructuredData { 53 template <typename N> class Integer; 54 55 public: 56 class Object; 57 class Array; 58 using UnsignedInteger = Integer<uint64_t>; 59 using SignedInteger = Integer<int64_t>; 60 class Float; 61 class Boolean; 62 class String; 63 class Dictionary; 64 class Generic; 65 66 typedef std::shared_ptr<Object> ObjectSP; 67 typedef std::shared_ptr<Array> ArraySP; 68 typedef std::shared_ptr<UnsignedInteger> UnsignedIntegerSP; 69 typedef std::shared_ptr<SignedInteger> SignedIntegerSP; 70 typedef std::shared_ptr<Float> FloatSP; 71 typedef std::shared_ptr<Boolean> BooleanSP; 72 typedef std::shared_ptr<String> StringSP; 73 typedef std::shared_ptr<Dictionary> DictionarySP; 74 typedef std::shared_ptr<Generic> GenericSP; 75 76 typedef std::variant<UnsignedIntegerSP, SignedIntegerSP> IntegerSP; 77 78 class Object : public std::enable_shared_from_this<Object> { 79 public: 80 Object(lldb::StructuredDataType t = lldb::eStructuredDataTypeInvalid) m_type(t)81 : m_type(t) {} 82 83 virtual ~Object() = default; 84 IsValid()85 virtual bool IsValid() const { return true; } 86 Clear()87 virtual void Clear() { m_type = lldb::eStructuredDataTypeInvalid; } 88 GetType()89 lldb::StructuredDataType GetType() const { return m_type; } 90 SetType(lldb::StructuredDataType t)91 void SetType(lldb::StructuredDataType t) { m_type = t; } 92 GetAsArray()93 Array *GetAsArray() { 94 return ((m_type == lldb::eStructuredDataTypeArray) 95 ? static_cast<Array *>(this) 96 : nullptr); 97 } 98 GetAsDictionary()99 Dictionary *GetAsDictionary() { 100 return ((m_type == lldb::eStructuredDataTypeDictionary) 101 ? static_cast<Dictionary *>(this) 102 : nullptr); 103 } 104 GetAsUnsignedInteger()105 UnsignedInteger *GetAsUnsignedInteger() { 106 // NOTE: For backward compatibility, eStructuredDataTypeInteger is 107 // the same as eStructuredDataTypeUnsignedInteger. 108 return ((m_type == lldb::eStructuredDataTypeInteger || 109 m_type == lldb::eStructuredDataTypeUnsignedInteger) 110 ? static_cast<UnsignedInteger *>(this) 111 : nullptr); 112 } 113 GetAsSignedInteger()114 SignedInteger *GetAsSignedInteger() { 115 return ((m_type == lldb::eStructuredDataTypeSignedInteger) 116 ? static_cast<SignedInteger *>(this) 117 : nullptr); 118 } 119 120 uint64_t GetUnsignedIntegerValue(uint64_t fail_value = 0) { 121 UnsignedInteger *integer = GetAsUnsignedInteger(); 122 return ((integer != nullptr) ? integer->GetValue() : fail_value); 123 } 124 125 int64_t GetSignedIntegerValue(int64_t fail_value = 0) { 126 SignedInteger *integer = GetAsSignedInteger(); 127 return ((integer != nullptr) ? integer->GetValue() : fail_value); 128 } 129 GetAsFloat()130 Float *GetAsFloat() { 131 return ((m_type == lldb::eStructuredDataTypeFloat) 132 ? static_cast<Float *>(this) 133 : nullptr); 134 } 135 136 double GetFloatValue(double fail_value = 0.0) { 137 Float *f = GetAsFloat(); 138 return ((f != nullptr) ? f->GetValue() : fail_value); 139 } 140 GetAsBoolean()141 Boolean *GetAsBoolean() { 142 return ((m_type == lldb::eStructuredDataTypeBoolean) 143 ? static_cast<Boolean *>(this) 144 : nullptr); 145 } 146 147 bool GetBooleanValue(bool fail_value = false) { 148 Boolean *b = GetAsBoolean(); 149 return ((b != nullptr) ? b->GetValue() : fail_value); 150 } 151 GetAsString()152 String *GetAsString() { 153 return ((m_type == lldb::eStructuredDataTypeString) 154 ? static_cast<String *>(this) 155 : nullptr); 156 } 157 158 llvm::StringRef GetStringValue(const char *fail_value = nullptr) { 159 String *s = GetAsString(); 160 if (s) 161 return s->GetValue(); 162 163 return fail_value; 164 } 165 GetAsGeneric()166 Generic *GetAsGeneric() { 167 return ((m_type == lldb::eStructuredDataTypeGeneric) 168 ? static_cast<Generic *>(this) 169 : nullptr); 170 } 171 172 ObjectSP GetObjectForDotSeparatedPath(llvm::StringRef path); 173 174 void DumpToStdout(bool pretty_print = true) const; 175 176 virtual void Serialize(llvm::json::OStream &s) const = 0; 177 178 void Dump(lldb_private::Stream &s, bool pretty_print = true) const { 179 llvm::json::OStream jso(s.AsRawOstream(), pretty_print ? 2 : 0); 180 Serialize(jso); 181 } 182 GetDescription(lldb_private::Stream & s)183 virtual void GetDescription(lldb_private::Stream &s) const { 184 s.IndentMore(); 185 Dump(s, false); 186 s.IndentLess(); 187 } 188 189 private: 190 lldb::StructuredDataType m_type; 191 }; 192 193 class Array : public Object { 194 public: Array()195 Array() : Object(lldb::eStructuredDataTypeArray) {} 196 197 ~Array() override = default; 198 199 bool ForEach(std::function<bool (Object * object)> const & foreach_callback)200 ForEach(std::function<bool(Object *object)> const &foreach_callback) const { 201 for (const auto &object_sp : m_items) { 202 if (!foreach_callback(object_sp.get())) 203 return false; 204 } 205 return true; 206 } 207 GetSize()208 size_t GetSize() const { return m_items.size(); } 209 210 ObjectSP operator[](size_t idx) { 211 if (idx < m_items.size()) 212 return m_items[idx]; 213 return ObjectSP(); 214 } 215 GetItemAtIndex(size_t idx)216 ObjectSP GetItemAtIndex(size_t idx) const { 217 assert(idx < GetSize()); 218 if (idx < m_items.size()) 219 return m_items[idx]; 220 return ObjectSP(); 221 } 222 223 template <class IntType> GetItemAtIndexAsInteger(size_t idx,IntType & result)224 bool GetItemAtIndexAsInteger(size_t idx, IntType &result) const { 225 ObjectSP value_sp = GetItemAtIndex(idx); 226 if (value_sp.get()) { 227 if constexpr (std::numeric_limits<IntType>::is_signed) { 228 if (auto signed_value = value_sp->GetAsSignedInteger()) { 229 result = static_cast<IntType>(signed_value->GetValue()); 230 return true; 231 } 232 } else { 233 if (auto unsigned_value = value_sp->GetAsUnsignedInteger()) { 234 result = static_cast<IntType>(unsigned_value->GetValue()); 235 return true; 236 } 237 } 238 } 239 return false; 240 } 241 242 template <class IntType> GetItemAtIndexAsInteger(size_t idx,IntType & result,IntType default_val)243 bool GetItemAtIndexAsInteger(size_t idx, IntType &result, 244 IntType default_val) const { 245 bool success = GetItemAtIndexAsInteger(idx, result); 246 if (!success) 247 result = default_val; 248 return success; 249 } 250 GetItemAtIndexAsString(size_t idx)251 std::optional<llvm::StringRef> GetItemAtIndexAsString(size_t idx) const { 252 if (auto item_sp = GetItemAtIndex(idx)) { 253 if (auto *string_value = item_sp->GetAsString()) 254 return string_value->GetValue(); 255 } 256 return {}; 257 } 258 259 /// Retrieves the element at index \a idx from a StructuredData::Array if it 260 /// is a Dictionary. 261 /// 262 /// \param[in] idx 263 /// The index of the element to retrieve. 264 /// 265 /// \return 266 /// If the element at index \a idx is a Dictionary, this method returns a 267 /// valid pointer to the Dictionary wrapped in a std::optional. If the 268 /// element is not a Dictionary or the index is invalid, this returns 269 /// std::nullopt. Note that the underlying Dictionary pointer is never 270 /// nullptr. GetItemAtIndexAsDictionary(size_t idx)271 std::optional<Dictionary *> GetItemAtIndexAsDictionary(size_t idx) const { 272 if (auto item_sp = GetItemAtIndex(idx)) { 273 if (auto *dict = item_sp->GetAsDictionary()) 274 return dict; 275 } 276 return {}; 277 } 278 Push(const ObjectSP & item)279 void Push(const ObjectSP &item) { m_items.push_back(item); } 280 AddItem(const ObjectSP & item)281 void AddItem(const ObjectSP &item) { m_items.push_back(item); } 282 AddIntegerItem(T value)283 template <typename T> void AddIntegerItem(T value) { 284 static_assert(std::is_integral<T>::value || 285 std::is_floating_point<T>::value, 286 "value type should be integral"); 287 if constexpr (std::numeric_limits<T>::is_signed) 288 AddItem(std::make_shared<SignedInteger>(value)); 289 else 290 AddItem(std::make_shared<UnsignedInteger>(value)); 291 } 292 AddFloatItem(double value)293 void AddFloatItem(double value) { AddItem(std::make_shared<Float>(value)); } 294 AddStringItem(llvm::StringRef value)295 void AddStringItem(llvm::StringRef value) { 296 AddItem(std::make_shared<String>(std::move(value))); 297 } 298 AddBooleanItem(bool value)299 void AddBooleanItem(bool value) { 300 AddItem(std::make_shared<Boolean>(value)); 301 } 302 303 void Serialize(llvm::json::OStream &s) const override; 304 305 void GetDescription(lldb_private::Stream &s) const override; 306 307 protected: 308 typedef std::vector<ObjectSP> collection; 309 collection m_items; 310 }; 311 312 private: 313 template <typename N> class Integer : public Object { 314 static_assert(std::is_integral<N>::value, "N must be an integral type"); 315 316 public: 317 Integer(N i = 0) 318 : Object(std::numeric_limits<N>::is_signed 319 ? lldb::eStructuredDataTypeSignedInteger 320 : lldb::eStructuredDataTypeUnsignedInteger), 321 m_value(i) {} 322 ~Integer() override = default; 323 SetValue(N value)324 void SetValue(N value) { m_value = value; } 325 GetValue()326 N GetValue() { return m_value; } 327 Serialize(llvm::json::OStream & s)328 void Serialize(llvm::json::OStream &s) const override { 329 s.value(static_cast<N>(m_value)); 330 } 331 GetDescription(lldb_private::Stream & s)332 void GetDescription(lldb_private::Stream &s) const override { 333 s.Printf(std::numeric_limits<N>::is_signed ? "%" PRId64 : "%" PRIu64, 334 static_cast<N>(m_value)); 335 } 336 337 protected: 338 N m_value; 339 }; 340 341 public: 342 class Float : public Object { 343 public: 344 Float(double d = 0.0) Object(lldb::eStructuredDataTypeFloat)345 : Object(lldb::eStructuredDataTypeFloat), m_value(d) {} 346 347 ~Float() override = default; 348 SetValue(double value)349 void SetValue(double value) { m_value = value; } 350 GetValue()351 double GetValue() { return m_value; } 352 353 void Serialize(llvm::json::OStream &s) const override; 354 355 void GetDescription(lldb_private::Stream &s) const override; 356 357 protected: 358 double m_value; 359 }; 360 361 class Boolean : public Object { 362 public: 363 Boolean(bool b = false) Object(lldb::eStructuredDataTypeBoolean)364 : Object(lldb::eStructuredDataTypeBoolean), m_value(b) {} 365 366 ~Boolean() override = default; 367 SetValue(bool value)368 void SetValue(bool value) { m_value = value; } 369 GetValue()370 bool GetValue() { return m_value; } 371 372 void Serialize(llvm::json::OStream &s) const override; 373 374 void GetDescription(lldb_private::Stream &s) const override; 375 376 protected: 377 bool m_value; 378 }; 379 380 class String : public Object { 381 public: String()382 String() : Object(lldb::eStructuredDataTypeString) {} String(llvm::StringRef S)383 explicit String(llvm::StringRef S) 384 : Object(lldb::eStructuredDataTypeString), m_value(S) {} 385 SetValue(llvm::StringRef S)386 void SetValue(llvm::StringRef S) { m_value = std::string(S); } 387 GetValue()388 llvm::StringRef GetValue() { return m_value; } 389 390 void Serialize(llvm::json::OStream &s) const override; 391 392 void GetDescription(lldb_private::Stream &s) const override; 393 394 protected: 395 std::string m_value; 396 }; 397 398 class Dictionary : public Object { 399 public: Dictionary()400 Dictionary() : Object(lldb::eStructuredDataTypeDictionary) {} 401 Dictionary(ObjectSP obj_sp)402 Dictionary(ObjectSP obj_sp) : Object(lldb::eStructuredDataTypeDictionary) { 403 if (!obj_sp || obj_sp->GetType() != lldb::eStructuredDataTypeDictionary) { 404 SetType(lldb::eStructuredDataTypeInvalid); 405 return; 406 } 407 408 Dictionary *dict = obj_sp->GetAsDictionary(); 409 m_dict = dict->m_dict; 410 } 411 412 ~Dictionary() override = default; 413 GetSize()414 size_t GetSize() const { return m_dict.size(); } 415 ForEach(std::function<bool (llvm::StringRef key,Object * object)> const & callback)416 void ForEach(std::function<bool(llvm::StringRef key, Object *object)> const 417 &callback) const { 418 for (const auto &pair : m_dict) { 419 if (!callback(pair.first(), pair.second.get())) 420 break; 421 } 422 } 423 GetKeys()424 ArraySP GetKeys() const { 425 auto array_sp = std::make_shared<Array>(); 426 for (auto iter = m_dict.begin(); iter != m_dict.end(); ++iter) { 427 auto key_object_sp = std::make_shared<String>(iter->first()); 428 array_sp->Push(key_object_sp); 429 } 430 return array_sp; 431 } 432 GetValueForKey(llvm::StringRef key)433 ObjectSP GetValueForKey(llvm::StringRef key) const { 434 return m_dict.lookup(key); 435 } 436 GetValueForKeyAsBoolean(llvm::StringRef key,bool & result)437 bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const { 438 bool success = false; 439 ObjectSP value_sp = GetValueForKey(key); 440 if (value_sp.get()) { 441 Boolean *result_ptr = value_sp->GetAsBoolean(); 442 if (result_ptr) { 443 result = result_ptr->GetValue(); 444 success = true; 445 } 446 } 447 return success; 448 } 449 450 template <class IntType> GetValueForKeyAsInteger(llvm::StringRef key,IntType & result)451 bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const { 452 ObjectSP value_sp = GetValueForKey(key); 453 if (value_sp) { 454 if constexpr (std::numeric_limits<IntType>::is_signed) { 455 if (auto signed_value = value_sp->GetAsSignedInteger()) { 456 result = static_cast<IntType>(signed_value->GetValue()); 457 return true; 458 } 459 } else { 460 if (auto unsigned_value = value_sp->GetAsUnsignedInteger()) { 461 result = static_cast<IntType>(unsigned_value->GetValue()); 462 return true; 463 } 464 } 465 } 466 return false; 467 } 468 469 template <class IntType> GetValueForKeyAsInteger(llvm::StringRef key,IntType & result,IntType default_val)470 bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result, 471 IntType default_val) const { 472 bool success = GetValueForKeyAsInteger<IntType>(key, result); 473 if (!success) 474 result = default_val; 475 return success; 476 } 477 GetValueForKeyAsString(llvm::StringRef key,llvm::StringRef & result)478 bool GetValueForKeyAsString(llvm::StringRef key, 479 llvm::StringRef &result) const { 480 ObjectSP value_sp = GetValueForKey(key); 481 if (value_sp.get()) { 482 if (auto string_value = value_sp->GetAsString()) { 483 result = string_value->GetValue(); 484 return true; 485 } 486 } 487 return false; 488 } 489 GetValueForKeyAsString(llvm::StringRef key,llvm::StringRef & result,const char * default_val)490 bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result, 491 const char *default_val) const { 492 bool success = GetValueForKeyAsString(key, result); 493 if (!success) { 494 if (default_val) 495 result = default_val; 496 else 497 result = llvm::StringRef(); 498 } 499 return success; 500 } 501 GetValueForKeyAsDictionary(llvm::StringRef key,Dictionary * & result)502 bool GetValueForKeyAsDictionary(llvm::StringRef key, 503 Dictionary *&result) const { 504 result = nullptr; 505 ObjectSP value_sp = GetValueForKey(key); 506 if (value_sp.get()) { 507 result = value_sp->GetAsDictionary(); 508 return (result != nullptr); 509 } 510 return false; 511 } 512 GetValueForKeyAsArray(llvm::StringRef key,Array * & result)513 bool GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const { 514 result = nullptr; 515 ObjectSP value_sp = GetValueForKey(key); 516 if (value_sp.get()) { 517 result = value_sp->GetAsArray(); 518 return (result != nullptr); 519 } 520 return false; 521 } 522 HasKey(llvm::StringRef key)523 bool HasKey(llvm::StringRef key) const { return m_dict.contains(key); } 524 AddItem(llvm::StringRef key,ObjectSP value_sp)525 void AddItem(llvm::StringRef key, ObjectSP value_sp) { 526 m_dict.insert_or_assign(key, std::move(value_sp)); 527 } 528 AddIntegerItem(llvm::StringRef key,T value)529 template <typename T> void AddIntegerItem(llvm::StringRef key, T value) { 530 static_assert(std::is_integral<T>::value || 531 std::is_floating_point<T>::value, 532 "value type should be integral"); 533 if constexpr (std::numeric_limits<T>::is_signed) 534 AddItem(key, std::make_shared<SignedInteger>(value)); 535 else 536 AddItem(key, std::make_shared<UnsignedInteger>(value)); 537 } 538 AddFloatItem(llvm::StringRef key,double value)539 void AddFloatItem(llvm::StringRef key, double value) { 540 AddItem(key, std::make_shared<Float>(value)); 541 } 542 AddStringItem(llvm::StringRef key,llvm::StringRef value)543 void AddStringItem(llvm::StringRef key, llvm::StringRef value) { 544 AddItem(key, std::make_shared<String>(std::move(value))); 545 } 546 AddBooleanItem(llvm::StringRef key,bool value)547 void AddBooleanItem(llvm::StringRef key, bool value) { 548 AddItem(key, std::make_shared<Boolean>(value)); 549 } 550 551 void Serialize(llvm::json::OStream &s) const override; 552 553 void GetDescription(lldb_private::Stream &s) const override; 554 555 protected: 556 llvm::StringMap<ObjectSP> m_dict; 557 }; 558 559 class Null : public Object { 560 public: Null()561 Null() : Object(lldb::eStructuredDataTypeNull) {} 562 563 ~Null() override = default; 564 IsValid()565 bool IsValid() const override { return false; } 566 567 void Serialize(llvm::json::OStream &s) const override; 568 569 void GetDescription(lldb_private::Stream &s) const override; 570 }; 571 572 class Generic : public Object { 573 public: 574 explicit Generic(void *object = nullptr) Object(lldb::eStructuredDataTypeGeneric)575 : Object(lldb::eStructuredDataTypeGeneric), m_object(object) {} 576 SetValue(void * value)577 void SetValue(void *value) { m_object = value; } 578 GetValue()579 void *GetValue() const { return m_object; } 580 IsValid()581 bool IsValid() const override { return m_object != nullptr; } 582 583 void Serialize(llvm::json::OStream &s) const override; 584 585 void GetDescription(lldb_private::Stream &s) const override; 586 587 private: 588 void *m_object; 589 }; 590 591 static ObjectSP ParseJSON(llvm::StringRef json_text); 592 static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error); 593 static bool IsRecordType(const ObjectSP object_sp); 594 }; 595 596 } // namespace lldb_private 597 598 #endif // LLDB_UTILITY_STRUCTUREDDATA_H 599