1 //===-- LibCxxUnorderedMap.cpp ----------------------------------*- 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 // C Includes 11 // C++ Includes 12 // Other libraries and framework includes 13 // Project includes 14 #include "LibCxx.h" 15 16 #include "lldb/Core/DataBufferHeap.h" 17 #include "lldb/Core/Error.h" 18 #include "lldb/Core/Stream.h" 19 #include "lldb/Core/ValueObject.h" 20 #include "lldb/Core/ValueObjectConstResult.h" 21 #include "lldb/DataFormatters/FormattersHelpers.h" 22 #include "lldb/Host/Endian.h" 23 #include "lldb/Symbol/ClangASTContext.h" 24 #include "lldb/Target/Target.h" 25 26 using namespace lldb; 27 using namespace lldb_private; 28 using namespace lldb_private::formatters; 29 30 namespace lldb_private { 31 namespace formatters { 32 class LibcxxStdUnorderedMapSyntheticFrontEnd 33 : public SyntheticChildrenFrontEnd { 34 public: 35 LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 36 37 ~LibcxxStdUnorderedMapSyntheticFrontEnd() override = default; 38 39 size_t CalculateNumChildren() override; 40 41 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 42 43 bool Update() override; 44 45 bool MightHaveChildren() override; 46 47 size_t GetIndexOfChildWithName(const ConstString &name) override; 48 49 private: 50 ValueObject *m_tree; 51 size_t m_num_elements; 52 ValueObject *m_next_element; 53 std::vector<std::pair<ValueObject *, uint64_t>> m_elements_cache; 54 }; 55 } // namespace formatters 56 } // namespace lldb_private 57 58 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 59 LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 60 : SyntheticChildrenFrontEnd(*valobj_sp), m_tree(nullptr), m_num_elements(0), 61 m_next_element(nullptr), m_elements_cache() { 62 if (valobj_sp) 63 Update(); 64 } 65 66 size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 67 CalculateNumChildren() { 68 if (m_num_elements != UINT32_MAX) 69 return m_num_elements; 70 return 0; 71 } 72 73 lldb::ValueObjectSP lldb_private::formatters:: 74 LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 75 if (idx >= CalculateNumChildren()) 76 return lldb::ValueObjectSP(); 77 if (m_tree == nullptr) 78 return lldb::ValueObjectSP(); 79 80 while (idx >= m_elements_cache.size()) { 81 if (m_next_element == nullptr) 82 return lldb::ValueObjectSP(); 83 84 Error error; 85 ValueObjectSP node_sp = m_next_element->Dereference(error); 86 if (!node_sp || error.Fail()) 87 return lldb::ValueObjectSP(); 88 89 ValueObjectSP value_sp = 90 node_sp->GetChildMemberWithName(ConstString("__value_"), true); 91 ValueObjectSP hash_sp = 92 node_sp->GetChildMemberWithName(ConstString("__hash_"), true); 93 if (!hash_sp || !value_sp) 94 return lldb::ValueObjectSP(); 95 m_elements_cache.push_back( 96 {value_sp.get(), hash_sp->GetValueAsUnsigned(0)}); 97 m_next_element = 98 node_sp->GetChildMemberWithName(ConstString("__next_"), true).get(); 99 if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0) 100 m_next_element = nullptr; 101 } 102 103 std::pair<ValueObject *, uint64_t> val_hash = m_elements_cache[idx]; 104 if (!val_hash.first) 105 return lldb::ValueObjectSP(); 106 StreamString stream; 107 stream.Printf("[%" PRIu64 "]", (uint64_t)idx); 108 DataExtractor data; 109 Error error; 110 val_hash.first->GetData(data, error); 111 if (error.Fail()) 112 return lldb::ValueObjectSP(); 113 const bool thread_and_frame_only_if_stopped = true; 114 ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock( 115 thread_and_frame_only_if_stopped); 116 return CreateValueObjectFromData(stream.GetData(), data, exe_ctx, 117 val_hash.first->GetCompilerType()); 118 } 119 120 bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 121 Update() { 122 m_num_elements = UINT32_MAX; 123 m_next_element = nullptr; 124 m_elements_cache.clear(); 125 ValueObjectSP table_sp = 126 m_backend.GetChildMemberWithName(ConstString("__table_"), true); 127 if (!table_sp) 128 return false; 129 ValueObjectSP num_elements_sp = table_sp->GetChildAtNamePath( 130 {ConstString("__p2_"), ConstString("__first_")}); 131 if (!num_elements_sp) 132 return false; 133 m_num_elements = num_elements_sp->GetValueAsUnsigned(0); 134 m_tree = 135 table_sp 136 ->GetChildAtNamePath({ConstString("__p1_"), ConstString("__first_"), 137 ConstString("__next_")}) 138 .get(); 139 if (m_num_elements > 0) 140 m_next_element = 141 table_sp 142 ->GetChildAtNamePath({ConstString("__p1_"), ConstString("__first_"), 143 ConstString("__next_")}) 144 .get(); 145 return false; 146 } 147 148 bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 149 MightHaveChildren() { 150 return true; 151 } 152 153 size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 154 GetIndexOfChildWithName(const ConstString &name) { 155 return ExtractIndexFromString(name.GetCString()); 156 } 157 158 SyntheticChildrenFrontEnd * 159 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator( 160 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 161 return (valobj_sp ? new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp) 162 : nullptr); 163 } 164