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 CompilerType m_element_type; 51 CompilerType m_node_type; 52 ValueObject *m_tree; 53 size_t m_num_elements; 54 ValueObject *m_next_element; 55 std::vector<std::pair<ValueObject *, uint64_t>> m_elements_cache; 56 }; 57 } // namespace formatters 58 } // namespace lldb_private 59 60 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 61 LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 62 : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type(), m_tree(nullptr), 63 m_num_elements(0), m_next_element(nullptr), m_elements_cache() { 64 if (valobj_sp) 65 Update(); 66 } 67 68 size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 69 CalculateNumChildren() { 70 if (m_num_elements != UINT32_MAX) 71 return m_num_elements; 72 return 0; 73 } 74 75 lldb::ValueObjectSP lldb_private::formatters:: 76 LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 77 if (idx >= CalculateNumChildren()) 78 return lldb::ValueObjectSP(); 79 if (m_tree == nullptr) 80 return lldb::ValueObjectSP(); 81 82 while (idx >= m_elements_cache.size()) { 83 if (m_next_element == nullptr) 84 return lldb::ValueObjectSP(); 85 86 Error error; 87 ValueObjectSP node_sp = m_next_element->Dereference(error); 88 if (!node_sp || error.Fail()) 89 return lldb::ValueObjectSP(); 90 91 ValueObjectSP value_sp = 92 node_sp->GetChildMemberWithName(ConstString("__value_"), true); 93 ValueObjectSP hash_sp = 94 node_sp->GetChildMemberWithName(ConstString("__hash_"), true); 95 if (!hash_sp || !value_sp) { 96 if (!m_element_type) { 97 auto first_sp = m_backend.GetChildAtNamePath({ConstString("__table_"), 98 ConstString("__p1_"), 99 ConstString("__first_")}); 100 if (!first_sp) 101 return nullptr; 102 m_element_type = first_sp->GetCompilerType(); 103 lldb::TemplateArgumentKind kind; 104 m_element_type = m_element_type.GetTemplateArgument(0, kind); 105 m_element_type = m_element_type.GetPointeeType(); 106 m_node_type = m_element_type; 107 m_element_type = m_element_type.GetTemplateArgument(0, kind); 108 std::string name; 109 m_element_type = 110 m_element_type.GetFieldAtIndex(0, name, nullptr, nullptr, nullptr); 111 m_element_type = m_element_type.GetTypedefedType(); 112 } 113 if (!m_node_type) 114 return nullptr; 115 node_sp = node_sp->Cast(m_node_type); 116 value_sp = node_sp->GetChildMemberWithName(ConstString("__value_"), true); 117 hash_sp = node_sp->GetChildMemberWithName(ConstString("__hash_"), true); 118 if (!value_sp || !hash_sp) 119 return nullptr; 120 } 121 m_elements_cache.push_back( 122 {value_sp.get(), hash_sp->GetValueAsUnsigned(0)}); 123 m_next_element = 124 node_sp->GetChildMemberWithName(ConstString("__next_"), true).get(); 125 if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0) 126 m_next_element = nullptr; 127 } 128 129 std::pair<ValueObject *, uint64_t> val_hash = m_elements_cache[idx]; 130 if (!val_hash.first) 131 return lldb::ValueObjectSP(); 132 StreamString stream; 133 stream.Printf("[%" PRIu64 "]", (uint64_t)idx); 134 DataExtractor data; 135 Error error; 136 val_hash.first->GetData(data, error); 137 if (error.Fail()) 138 return lldb::ValueObjectSP(); 139 const bool thread_and_frame_only_if_stopped = true; 140 ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock( 141 thread_and_frame_only_if_stopped); 142 return CreateValueObjectFromData(stream.GetData(), data, exe_ctx, 143 val_hash.first->GetCompilerType()); 144 } 145 146 bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 147 Update() { 148 m_num_elements = UINT32_MAX; 149 m_next_element = nullptr; 150 m_elements_cache.clear(); 151 ValueObjectSP table_sp = 152 m_backend.GetChildMemberWithName(ConstString("__table_"), true); 153 if (!table_sp) 154 return false; 155 ValueObjectSP num_elements_sp = table_sp->GetChildAtNamePath( 156 {ConstString("__p2_"), ConstString("__first_")}); 157 if (!num_elements_sp) 158 return false; 159 m_num_elements = num_elements_sp->GetValueAsUnsigned(0); 160 m_tree = 161 table_sp 162 ->GetChildAtNamePath({ConstString("__p1_"), ConstString("__first_"), 163 ConstString("__next_")}) 164 .get(); 165 if (m_num_elements > 0) 166 m_next_element = 167 table_sp 168 ->GetChildAtNamePath({ConstString("__p1_"), ConstString("__first_"), 169 ConstString("__next_")}) 170 .get(); 171 return false; 172 } 173 174 bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 175 MightHaveChildren() { 176 return true; 177 } 178 179 size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 180 GetIndexOfChildWithName(const ConstString &name) { 181 return ExtractIndexFromString(name.GetCString()); 182 } 183 184 SyntheticChildrenFrontEnd * 185 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator( 186 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 187 return (valobj_sp ? new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp) 188 : nullptr); 189 } 190