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/ValueObject.h" 17 #include "lldb/Core/ValueObjectConstResult.h" 18 #include "lldb/DataFormatters/FormattersHelpers.h" 19 #include "lldb/Symbol/ClangASTContext.h" 20 #include "lldb/Target/Target.h" 21 #include "lldb/Utility/DataBufferHeap.h" 22 #include "lldb/Utility/Endian.h" 23 #include "lldb/Utility/Status.h" 24 #include "lldb/Utility/Stream.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 Status 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 p1_sp = m_backend.GetChildAtNamePath({ConstString("__table_"), 98 ConstString("__p1_")}); 99 if (!p1_sp) 100 return nullptr; 101 102 ValueObjectSP first_sp = nullptr; 103 switch (p1_sp->GetCompilerType().GetNumDirectBaseClasses()) { 104 case 1: 105 // Assume a pre llvm r300140 __compressed_pair implementation: 106 first_sp = p1_sp->GetChildMemberWithName(ConstString("__first_"), 107 true); 108 break; 109 case 2: { 110 // Assume a post llvm r300140 __compressed_pair implementation: 111 ValueObjectSP first_elem_parent_sp = 112 p1_sp->GetChildAtIndex(0, true); 113 first_sp = p1_sp->GetChildMemberWithName(ConstString("__value_"), 114 true); 115 break; 116 } 117 default: 118 return nullptr; 119 } 120 121 if (!first_sp) 122 return nullptr; 123 m_element_type = first_sp->GetCompilerType(); 124 m_element_type = m_element_type.GetTypeTemplateArgument(0); 125 m_element_type = m_element_type.GetPointeeType(); 126 m_node_type = m_element_type; 127 m_element_type = m_element_type.GetTypeTemplateArgument(0); 128 std::string name; 129 m_element_type = 130 m_element_type.GetFieldAtIndex(0, name, nullptr, nullptr, nullptr); 131 m_element_type = m_element_type.GetTypedefedType(); 132 } 133 if (!m_node_type) 134 return nullptr; 135 node_sp = node_sp->Cast(m_node_type); 136 value_sp = node_sp->GetChildMemberWithName(ConstString("__value_"), true); 137 hash_sp = node_sp->GetChildMemberWithName(ConstString("__hash_"), true); 138 if (!value_sp || !hash_sp) 139 return nullptr; 140 } 141 m_elements_cache.push_back( 142 {value_sp.get(), hash_sp->GetValueAsUnsigned(0)}); 143 m_next_element = 144 node_sp->GetChildMemberWithName(ConstString("__next_"), true).get(); 145 if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0) 146 m_next_element = nullptr; 147 } 148 149 std::pair<ValueObject *, uint64_t> val_hash = m_elements_cache[idx]; 150 if (!val_hash.first) 151 return lldb::ValueObjectSP(); 152 StreamString stream; 153 stream.Printf("[%" PRIu64 "]", (uint64_t)idx); 154 DataExtractor data; 155 Status error; 156 val_hash.first->GetData(data, error); 157 if (error.Fail()) 158 return lldb::ValueObjectSP(); 159 const bool thread_and_frame_only_if_stopped = true; 160 ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock( 161 thread_and_frame_only_if_stopped); 162 return CreateValueObjectFromData(stream.GetString(), data, exe_ctx, 163 val_hash.first->GetCompilerType()); 164 } 165 166 bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 167 Update() { 168 m_num_elements = UINT32_MAX; 169 m_next_element = nullptr; 170 m_elements_cache.clear(); 171 ValueObjectSP table_sp = 172 m_backend.GetChildMemberWithName(ConstString("__table_"), true); 173 if (!table_sp) 174 return false; 175 176 ValueObjectSP p2_sp = table_sp->GetChildMemberWithName( 177 ConstString("__p2_"), true); 178 ValueObjectSP num_elements_sp = nullptr; 179 llvm::SmallVector<ConstString, 3> next_path; 180 switch (p2_sp->GetCompilerType().GetNumDirectBaseClasses()) { 181 case 1: 182 // Assume a pre llvm r300140 __compressed_pair implementation: 183 num_elements_sp = p2_sp->GetChildMemberWithName( 184 ConstString("__first_"), true); 185 next_path.append({ConstString("__p1_"), ConstString("__first_"), 186 ConstString("__next_")}); 187 break; 188 case 2: { 189 // Assume a post llvm r300140 __compressed_pair implementation: 190 ValueObjectSP first_elem_parent = p2_sp->GetChildAtIndex(0, true); 191 num_elements_sp = first_elem_parent->GetChildMemberWithName( 192 ConstString("__value_"), true); 193 next_path.append({ConstString("__p1_"), ConstString("__value_"), 194 ConstString("__next_")}); 195 break; 196 } 197 default: 198 return false; 199 } 200 201 if (!num_elements_sp) 202 return false; 203 m_num_elements = num_elements_sp->GetValueAsUnsigned(0); 204 m_tree = table_sp->GetChildAtNamePath(next_path).get(); 205 if (m_num_elements > 0) 206 m_next_element = 207 table_sp->GetChildAtNamePath(next_path).get(); 208 return false; 209 } 210 211 bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 212 MightHaveChildren() { 213 return true; 214 } 215 216 size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 217 GetIndexOfChildWithName(const ConstString &name) { 218 return ExtractIndexFromString(name.GetCString()); 219 } 220 221 SyntheticChildrenFrontEnd * 222 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator( 223 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 224 return (valobj_sp ? new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp) 225 : nullptr); 226 } 227