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