1 //===-- LibCxxUnorderedMap.cpp --------------------------------------------===// 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 #include "LibCxx.h" 10 11 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 12 #include "lldb/Core/ValueObject.h" 13 #include "lldb/Core/ValueObjectConstResult.h" 14 #include "lldb/DataFormatters/FormattersHelpers.h" 15 #include "lldb/Target/Target.h" 16 #include "lldb/Utility/DataBufferHeap.h" 17 #include "lldb/Utility/Endian.h" 18 #include "lldb/Utility/Status.h" 19 #include "lldb/Utility/Stream.h" 20 21 using namespace lldb; 22 using namespace lldb_private; 23 using namespace lldb_private::formatters; 24 25 namespace lldb_private { 26 namespace formatters { 27 class LibcxxStdUnorderedMapSyntheticFrontEnd 28 : public SyntheticChildrenFrontEnd { 29 public: 30 LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 31 32 ~LibcxxStdUnorderedMapSyntheticFrontEnd() override = default; 33 34 size_t CalculateNumChildren() override; 35 36 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 37 38 bool Update() override; 39 40 bool MightHaveChildren() override; 41 42 size_t GetIndexOfChildWithName(ConstString name) override; 43 44 private: 45 CompilerType m_element_type; 46 CompilerType m_node_type; 47 ValueObject *m_tree = nullptr; 48 size_t m_num_elements = 0; 49 ValueObject *m_next_element = nullptr; 50 std::vector<std::pair<ValueObject *, uint64_t>> m_elements_cache; 51 }; 52 } // namespace formatters 53 } // namespace lldb_private 54 55 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 56 LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 57 : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type(), 58 m_elements_cache() { 59 if (valobj_sp) 60 Update(); 61 } 62 63 size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 64 CalculateNumChildren() { 65 return m_num_elements; 66 } 67 68 lldb::ValueObjectSP lldb_private::formatters:: 69 LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 70 if (idx >= CalculateNumChildren()) 71 return lldb::ValueObjectSP(); 72 if (m_tree == nullptr) 73 return lldb::ValueObjectSP(); 74 75 while (idx >= m_elements_cache.size()) { 76 if (m_next_element == nullptr) 77 return lldb::ValueObjectSP(); 78 79 Status error; 80 ValueObjectSP node_sp = m_next_element->Dereference(error); 81 if (!node_sp || error.Fail()) 82 return lldb::ValueObjectSP(); 83 84 ValueObjectSP value_sp = 85 node_sp->GetChildMemberWithName(ConstString("__value_"), true); 86 ValueObjectSP hash_sp = 87 node_sp->GetChildMemberWithName(ConstString("__hash_"), true); 88 if (!hash_sp || !value_sp) { 89 if (!m_element_type) { 90 auto p1_sp = m_backend.GetChildAtNamePath({ConstString("__table_"), 91 ConstString("__p1_")}); 92 if (!p1_sp) 93 return nullptr; 94 95 ValueObjectSP first_sp = nullptr; 96 switch (p1_sp->GetCompilerType().GetNumDirectBaseClasses()) { 97 case 1: 98 // Assume a pre llvm r300140 __compressed_pair implementation: 99 first_sp = p1_sp->GetChildMemberWithName(ConstString("__first_"), 100 true); 101 break; 102 case 2: { 103 // Assume a post llvm r300140 __compressed_pair implementation: 104 ValueObjectSP first_elem_parent_sp = 105 p1_sp->GetChildAtIndex(0, true); 106 first_sp = p1_sp->GetChildMemberWithName(ConstString("__value_"), 107 true); 108 break; 109 } 110 default: 111 return nullptr; 112 } 113 114 if (!first_sp) 115 return nullptr; 116 m_element_type = first_sp->GetCompilerType(); 117 m_element_type = m_element_type.GetTypeTemplateArgument(0); 118 m_element_type = m_element_type.GetPointeeType(); 119 m_node_type = m_element_type; 120 m_element_type = m_element_type.GetTypeTemplateArgument(0); 121 std::string name; 122 m_element_type = 123 m_element_type.GetFieldAtIndex(0, name, nullptr, nullptr, nullptr); 124 m_element_type = m_element_type.GetTypedefedType(); 125 } 126 if (!m_node_type) 127 return nullptr; 128 node_sp = node_sp->Cast(m_node_type); 129 value_sp = node_sp->GetChildMemberWithName(ConstString("__value_"), true); 130 hash_sp = node_sp->GetChildMemberWithName(ConstString("__hash_"), true); 131 if (!value_sp || !hash_sp) 132 return nullptr; 133 } 134 m_elements_cache.push_back( 135 {value_sp.get(), hash_sp->GetValueAsUnsigned(0)}); 136 m_next_element = 137 node_sp->GetChildMemberWithName(ConstString("__next_"), true).get(); 138 if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0) 139 m_next_element = nullptr; 140 } 141 142 std::pair<ValueObject *, uint64_t> val_hash = m_elements_cache[idx]; 143 if (!val_hash.first) 144 return lldb::ValueObjectSP(); 145 StreamString stream; 146 stream.Printf("[%" PRIu64 "]", (uint64_t)idx); 147 DataExtractor data; 148 Status error; 149 val_hash.first->GetData(data, error); 150 if (error.Fail()) 151 return lldb::ValueObjectSP(); 152 const bool thread_and_frame_only_if_stopped = true; 153 ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock( 154 thread_and_frame_only_if_stopped); 155 return CreateValueObjectFromData(stream.GetString(), data, exe_ctx, 156 val_hash.first->GetCompilerType()); 157 } 158 159 bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 160 Update() { 161 m_num_elements = 0; 162 m_next_element = nullptr; 163 m_elements_cache.clear(); 164 ValueObjectSP table_sp = 165 m_backend.GetChildMemberWithName(ConstString("__table_"), true); 166 if (!table_sp) 167 return false; 168 169 ValueObjectSP p2_sp = table_sp->GetChildMemberWithName( 170 ConstString("__p2_"), true); 171 ValueObjectSP num_elements_sp = nullptr; 172 llvm::SmallVector<ConstString, 3> next_path; 173 switch (p2_sp->GetCompilerType().GetNumDirectBaseClasses()) { 174 case 1: 175 // Assume a pre llvm r300140 __compressed_pair implementation: 176 num_elements_sp = p2_sp->GetChildMemberWithName( 177 ConstString("__first_"), true); 178 next_path.append({ConstString("__p1_"), ConstString("__first_"), 179 ConstString("__next_")}); 180 break; 181 case 2: { 182 // Assume a post llvm r300140 __compressed_pair implementation: 183 ValueObjectSP first_elem_parent = p2_sp->GetChildAtIndex(0, true); 184 num_elements_sp = first_elem_parent->GetChildMemberWithName( 185 ConstString("__value_"), true); 186 next_path.append({ConstString("__p1_"), ConstString("__value_"), 187 ConstString("__next_")}); 188 break; 189 } 190 default: 191 return false; 192 } 193 194 if (!num_elements_sp) 195 return false; 196 197 m_tree = table_sp->GetChildAtNamePath(next_path).get(); 198 if (m_tree == nullptr) 199 return false; 200 201 m_num_elements = num_elements_sp->GetValueAsUnsigned(0); 202 203 if (m_num_elements > 0) 204 m_next_element = 205 table_sp->GetChildAtNamePath(next_path).get(); 206 return false; 207 } 208 209 bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 210 MightHaveChildren() { 211 return true; 212 } 213 214 size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 215 GetIndexOfChildWithName(ConstString name) { 216 return ExtractIndexFromString(name.GetCString()); 217 } 218 219 SyntheticChildrenFrontEnd * 220 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator( 221 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 222 return (valobj_sp ? new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp) 223 : nullptr); 224 } 225