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