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/DataBufferHeap.h" 17 #include "lldb/Core/Error.h" 18 #include "lldb/Core/Stream.h" 19 #include "lldb/Core/ValueObject.h" 20 #include "lldb/Core/ValueObjectConstResult.h" 21 #include "lldb/DataFormatters/FormattersHelpers.h" 22 #include "lldb/Host/Endian.h" 23 #include "lldb/Symbol/ClangASTContext.h" 24 #include "lldb/Target/Target.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 : public SyntheticChildrenFrontEnd 33 { 34 public: 35 LibcxxStdUnorderedMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp); 36 37 ~LibcxxStdUnorderedMapSyntheticFrontEnd() override = default; 38 39 size_t 40 CalculateNumChildren() override; 41 42 lldb::ValueObjectSP 43 GetChildAtIndex(size_t idx) override; 44 45 bool 46 Update() override; 47 48 bool 49 MightHaveChildren() override; 50 51 size_t 52 GetIndexOfChildWithName(const ConstString &name) override; 53 54 private: 55 ValueObject* m_tree; 56 size_t m_num_elements; 57 ValueObject* m_next_element; 58 std::map<size_t,lldb::ValueObjectSP> m_children; 59 std::vector<std::pair<ValueObject*, uint64_t> > m_elements_cache; 60 }; 61 } // namespace formatters 62 } // namespace lldb_private 63 64 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::LibcxxStdUnorderedMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 65 SyntheticChildrenFrontEnd(*valobj_sp.get()), 66 m_tree(NULL), 67 m_num_elements(0), 68 m_next_element(nullptr), 69 m_children(), 70 m_elements_cache() 71 { 72 if (valobj_sp) 73 Update(); 74 } 75 76 size_t 77 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::CalculateNumChildren () 78 { 79 if (m_num_elements != UINT32_MAX) 80 return m_num_elements; 81 return 0; 82 } 83 84 lldb::ValueObjectSP 85 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex (size_t idx) 86 { 87 if (idx >= CalculateNumChildren()) 88 return lldb::ValueObjectSP(); 89 if (m_tree == NULL) 90 return lldb::ValueObjectSP(); 91 92 auto cached = m_children.find(idx); 93 if (cached != m_children.end()) 94 return cached->second; 95 96 while (idx >= m_elements_cache.size()) 97 { 98 if (m_next_element == nullptr) 99 return lldb::ValueObjectSP(); 100 101 Error error; 102 ValueObjectSP node_sp = m_next_element->Dereference(error); 103 if (!node_sp || error.Fail()) 104 return lldb::ValueObjectSP(); 105 106 ValueObjectSP value_sp = node_sp->GetChildMemberWithName(ConstString("__value_"), true); 107 ValueObjectSP hash_sp = node_sp->GetChildMemberWithName(ConstString("__hash_"), true); 108 if (!hash_sp || !value_sp) 109 return lldb::ValueObjectSP(); 110 m_elements_cache.push_back({value_sp.get(),hash_sp->GetValueAsUnsigned(0)}); 111 m_next_element = node_sp->GetChildMemberWithName(ConstString("__next_"),true).get(); 112 if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0) 113 m_next_element = nullptr; 114 } 115 116 std::pair<ValueObject*, uint64_t> val_hash = m_elements_cache[idx]; 117 if (!val_hash.first) 118 return lldb::ValueObjectSP(); 119 StreamString stream; 120 stream.Printf("[%" PRIu64 "]", (uint64_t)idx); 121 DataExtractor data; 122 Error error; 123 val_hash.first->GetData(data, error); 124 if (error.Fail()) 125 return lldb::ValueObjectSP(); 126 const bool thread_and_frame_only_if_stopped = true; 127 ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped); 128 return val_hash.first->CreateValueObjectFromData(stream.GetData(), 129 data, 130 exe_ctx, 131 val_hash.first->GetCompilerType()); 132 } 133 134 bool 135 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::Update() 136 { 137 m_num_elements = UINT32_MAX; 138 m_next_element = nullptr; 139 m_elements_cache.clear(); 140 m_children.clear(); 141 ValueObjectSP table_sp = m_backend.GetChildMemberWithName(ConstString("__table_"), true); 142 if (!table_sp) 143 return false; 144 ValueObjectSP num_elements_sp = table_sp->GetChildAtNamePath({ConstString("__p2_"),ConstString("__first_")}); 145 if (!num_elements_sp) 146 return false; 147 m_num_elements = num_elements_sp->GetValueAsUnsigned(0); 148 m_tree = table_sp->GetChildAtNamePath({ConstString("__p1_"),ConstString("__first_"),ConstString("__next_")}).get(); 149 if (m_num_elements > 0) 150 m_next_element = table_sp->GetChildAtNamePath({ConstString("__p1_"),ConstString("__first_"),ConstString("__next_")}).get(); 151 return false; 152 } 153 154 bool 155 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::MightHaveChildren () 156 { 157 return true; 158 } 159 160 size_t 161 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 162 { 163 return ExtractIndexFromString(name.GetCString()); 164 } 165 166 SyntheticChildrenFrontEnd* 167 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) 168 { 169 if (!valobj_sp) 170 return NULL; 171 return (new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp)); 172 } 173