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