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