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::
LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)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::
CalculateNumChildren()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::
GetChildAtIndex(size_t idx)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::
Update()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::
MightHaveChildren()208 MightHaveChildren() {
209 return true;
210 }
211
212 size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
GetIndexOfChildWithName(const ConstString & name)213 GetIndexOfChildWithName(const ConstString &name) {
214 return ExtractIndexFromString(name.GetCString());
215 }
216
217 SyntheticChildrenFrontEnd *
LibcxxStdUnorderedMapSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)218 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator(
219 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
220 return (valobj_sp ? new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp)
221 : nullptr);
222 }
223