LLDB  mainline
LibCxxUnorderedMap.cpp
Go to the documentation of this file.
1 //===-- LibCxxUnorderedMap.cpp --------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "LibCxx.h"
10 
12 #include "lldb/Core/ValueObject.h"
15 #include "lldb/Target/Target.h"
18 #include "lldb/Utility/Endian.h"
19 #include "lldb/Utility/Status.h"
20 #include "lldb/Utility/Stream.h"
21 #include "llvm/ADT/StringRef.h"
22 
23 using namespace lldb;
24 using namespace lldb_private;
25 using namespace lldb_private::formatters;
26 
27 namespace lldb_private {
28 namespace formatters {
30  : public SyntheticChildrenFrontEnd {
31 public:
32  LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
33 
34  ~LibcxxStdUnorderedMapSyntheticFrontEnd() override = default;
35 
36  size_t CalculateNumChildren() override;
37 
38  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
39 
40  bool Update() override;
41 
42  bool MightHaveChildren() override;
43 
44  size_t GetIndexOfChildWithName(ConstString name) override;
45 
46 private:
49  ValueObject *m_tree = nullptr;
50  size_t m_num_elements = 0;
51  ValueObject *m_next_element = nullptr;
52  std::vector<std::pair<ValueObject *, uint64_t>> m_elements_cache;
53 };
54 } // namespace formatters
55 } // namespace lldb_private
56 
58  LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
59  : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type(),
60  m_elements_cache() {
61  if (valobj_sp)
62  Update();
63 }
64 
67  return m_num_elements;
68 }
69 
70 static void consumeInlineNamespace(llvm::StringRef &name) {
71  // Delete past an inline namespace, if any: __[a-zA-Z0-9_]+::
72  auto scratch = name;
73  if (scratch.consume_front("__") && std::isalnum(scratch[0])) {
74  scratch = scratch.drop_while([](char c) { return std::isalnum(c); });
75  if (scratch.consume_front("::")) {
76  // Successfully consumed a namespace.
77  name = scratch;
78  }
79  }
80 }
81 
82 static bool isStdTemplate(ConstString type_name, llvm::StringRef type) {
83  llvm::StringRef name = type_name.GetStringRef();
84  // The type name may be prefixed with `std::__<inline-namespace>::`.
85  if (name.consume_front("std::"))
87  return name.consume_front(type) && name.startswith("<");
88 }
89 
90 static bool isUnorderedMap(ConstString type_name) {
91  return isStdTemplate(type_name, "unordered_map") ||
92  isStdTemplate(type_name, "unordered_multimap");
93 }
94 
95 lldb::ValueObjectSP lldb_private::formatters::
97  if (idx >= CalculateNumChildren())
98  return lldb::ValueObjectSP();
99  if (m_tree == nullptr)
100  return lldb::ValueObjectSP();
101 
102  while (idx >= m_elements_cache.size()) {
103  if (m_next_element == nullptr)
104  return lldb::ValueObjectSP();
105 
106  Status error;
107  ValueObjectSP node_sp = m_next_element->Dereference(error);
108  if (!node_sp || error.Fail())
109  return lldb::ValueObjectSP();
110 
111  ValueObjectSP value_sp =
112  node_sp->GetChildMemberWithName(ConstString("__value_"), true);
113  ValueObjectSP hash_sp =
114  node_sp->GetChildMemberWithName(ConstString("__hash_"), true);
115  if (!hash_sp || !value_sp) {
116  if (!m_element_type) {
117  auto p1_sp = m_backend.GetChildAtNamePath({ConstString("__table_"),
118  ConstString("__p1_")});
119  if (!p1_sp)
120  return nullptr;
121 
122  ValueObjectSP first_sp = nullptr;
123  switch (p1_sp->GetCompilerType().GetNumDirectBaseClasses()) {
124  case 1:
125  // Assume a pre llvm r300140 __compressed_pair implementation:
126  first_sp = p1_sp->GetChildMemberWithName(ConstString("__first_"),
127  true);
128  break;
129  case 2: {
130  // Assume a post llvm r300140 __compressed_pair implementation:
131  ValueObjectSP first_elem_parent_sp =
132  p1_sp->GetChildAtIndex(0, true);
133  first_sp = p1_sp->GetChildMemberWithName(ConstString("__value_"),
134  true);
135  break;
136  }
137  default:
138  return nullptr;
139  }
140 
141  if (!first_sp)
142  return nullptr;
143  m_element_type = first_sp->GetCompilerType();
144  m_element_type = m_element_type.GetTypeTemplateArgument(0);
145  m_element_type = m_element_type.GetPointeeType();
146  m_node_type = m_element_type;
147  m_element_type = m_element_type.GetTypeTemplateArgument(0);
148  // This synthetic provider is used for both unordered_(multi)map and
149  // unordered_(multi)set. For unordered_map, the element type has an
150  // additional type layer, an internal struct (`__hash_value_type`)
151  // that wraps a std::pair. Peel away the internal wrapper type - whose
152  // structure is of no value to users, to expose the std::pair. This
153  // matches the structure returned by the std::map synthetic provider.
154  if (isUnorderedMap(m_backend.GetTypeName())) {
155  std::string name;
156  CompilerType field_type = m_element_type.GetFieldAtIndex(
157  0, name, nullptr, nullptr, nullptr);
158  CompilerType actual_type = field_type.GetTypedefedType();
159  if (isStdTemplate(actual_type.GetTypeName(), "pair"))
160  m_element_type = actual_type;
161  }
162  }
163  if (!m_node_type)
164  return nullptr;
165  node_sp = node_sp->Cast(m_node_type);
166  value_sp = node_sp->GetChildMemberWithName(ConstString("__value_"), true);
167  hash_sp = node_sp->GetChildMemberWithName(ConstString("__hash_"), true);
168  if (!value_sp || !hash_sp)
169  return nullptr;
170  }
171  m_elements_cache.push_back(
172  {value_sp.get(), hash_sp->GetValueAsUnsigned(0)});
173  m_next_element =
174  node_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
175  if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0)
176  m_next_element = nullptr;
177  }
178 
179  std::pair<ValueObject *, uint64_t> val_hash = m_elements_cache[idx];
180  if (!val_hash.first)
181  return lldb::ValueObjectSP();
182  StreamString stream;
183  stream.Printf("[%" PRIu64 "]", (uint64_t)idx);
184  DataExtractor data;
185  Status error;
186  val_hash.first->GetData(data, error);
187  if (error.Fail())
188  return lldb::ValueObjectSP();
189  const bool thread_and_frame_only_if_stopped = true;
190  ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock(
191  thread_and_frame_only_if_stopped);
192  return CreateValueObjectFromData(stream.GetString(), data, exe_ctx,
193  m_element_type);
194 }
195 
198  m_num_elements = 0;
199  m_next_element = nullptr;
200  m_elements_cache.clear();
201  ValueObjectSP table_sp =
202  m_backend.GetChildMemberWithName(ConstString("__table_"), true);
203  if (!table_sp)
204  return false;
205 
206  ValueObjectSP p2_sp = table_sp->GetChildMemberWithName(
207  ConstString("__p2_"), true);
208  ValueObjectSP num_elements_sp = nullptr;
209  llvm::SmallVector<ConstString, 3> next_path;
210  switch (p2_sp->GetCompilerType().GetNumDirectBaseClasses()) {
211  case 1:
212  // Assume a pre llvm r300140 __compressed_pair implementation:
213  num_elements_sp = p2_sp->GetChildMemberWithName(
214  ConstString("__first_"), true);
215  next_path.append({ConstString("__p1_"), ConstString("__first_"),
216  ConstString("__next_")});
217  break;
218  case 2: {
219  // Assume a post llvm r300140 __compressed_pair implementation:
220  ValueObjectSP first_elem_parent = p2_sp->GetChildAtIndex(0, true);
221  num_elements_sp = first_elem_parent->GetChildMemberWithName(
222  ConstString("__value_"), true);
223  next_path.append({ConstString("__p1_"), ConstString("__value_"),
224  ConstString("__next_")});
225  break;
226  }
227  default:
228  return false;
229  }
230 
231  if (!num_elements_sp)
232  return false;
233 
234  m_tree = table_sp->GetChildAtNamePath(next_path).get();
235  if (m_tree == nullptr)
236  return false;
237 
238  m_num_elements = num_elements_sp->GetValueAsUnsigned(0);
239 
240  if (m_num_elements > 0)
241  m_next_element =
242  table_sp->GetChildAtNamePath(next_path).get();
243  return false;
244 }
245 
248  return true;
249 }
250 
253  return ExtractIndexFromString(name.GetCString());
254 }
255 
258  CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
259  return (valobj_sp ? new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp)
260  : nullptr);
261 }
lldb_private::ExecutionContext
Definition: ExecutionContext.h:292
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd
Definition: LibCxxUnorderedMap.cpp:29
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator
SyntheticChildrenFrontEnd * LibcxxStdUnorderedMapSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
Definition: LibCxxUnorderedMap.cpp:257
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::m_node_type
CompilerType m_node_type
Definition: LibCxxUnorderedMap.cpp:48
consumeInlineNamespace
static void consumeInlineNamespace(llvm::StringRef &name)
Definition: LibCxxUnorderedMap.cpp:70
lldb_private::CompilerType::GetTypeName
ConstString GetTypeName(bool BaseOnly=false) const
Definition: CompilerType.cpp:314
CalculateNumChildren
static size_t CalculateNumChildren(CompilerType container_type, CompilerType element_type, lldb_private::ExecutionContextScope *exe_scope=nullptr)
Definition: VectorType.cpp:171
lldb_private::SyntheticChildrenFrontEnd
Definition: TypeSynthetic.h:27
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::Update
bool Update() override
Definition: LibCxxUnorderedMap.cpp:197
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::m_elements_cache
std::vector< std::pair< ValueObject *, uint64_t > > m_elements_cache
Definition: LibCxxUnorderedMap.cpp:52
lldb_private::StreamString::GetString
llvm::StringRef GetString() const
Definition: StreamString.cpp:51
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::MightHaveChildren
bool MightHaveChildren() override
Definition: LibCxxUnorderedMap.cpp:247
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
Definition: LibCxxUnorderedMap.cpp:96
Target.h
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
lldb_private::DataExtractor
Definition: DataExtractor.h:48
lldb_private::ConstString::GetStringRef
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
Definition: ConstString.h:201
TypeSystemClang.h
lldb_private::ConstString
Definition: ConstString.h:39
lldb_private::StreamString
Definition: StreamString.h:23
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::m_element_type
CompilerType m_element_type
Definition: LibCxxUnorderedMap.cpp:47
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:40
ValueObject.h
ValueObjectConstResult.h
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::LibcxxStdUnorderedMapSyntheticFrontEnd
LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
Definition: LibCxxUnorderedMap.cpp:58
lldb_private::Status
Definition: Status.h:44
lldb_private::ValueObject
ValueObject:
Definition: ValueObject.h:105
lldb_private::ConstString::GetCString
const char * GetCString() const
Get the string value as a C string.
Definition: ConstString.h:215
lldb_private::CompilerType::GetTypedefedType
CompilerType GetTypedefedType() const
If the current object represents a typedef type, get the underlying type.
Definition: CompilerType.cpp:525
lldb_private::CompilerType
Generic representation of a type in a programming language.
Definition: CompilerType.h:35
lldb_private::Stream::Printf
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
Status.h
lldb_private::formatters
Definition: CXXFunctionPointer.h:15
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
LibCxx.h
isStdTemplate
static bool isStdTemplate(ConstString type_name, llvm::StringRef type)
Definition: LibCxxUnorderedMap.cpp:82
ConstString.h
Stream.h
lldb_private::CompilerType::GetFieldAtIndex
CompilerType GetFieldAtIndex(size_t idx, std::string &name, uint64_t *bit_offset_ptr, uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) const
Definition: CompilerType.cpp:611
lldb_private::CXXSyntheticChildren
Definition: TypeSynthetic.h:358
FormattersHelpers.h
lldb
Definition: SBAddress.h:15
Endian.h
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::GetIndexOfChildWithName
size_t GetIndexOfChildWithName(ConstString name) override
Definition: LibCxxUnorderedMap.cpp:252
lldb_private::formatters::ExtractIndexFromString
size_t ExtractIndexFromString(const char *item_name)
Definition: FormattersHelpers.cpp:99
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::CalculateNumChildren
size_t CalculateNumChildren() override
Definition: LibCxxUnorderedMap.cpp:66
DataBufferHeap.h
isUnorderedMap
static bool isUnorderedMap(ConstString type_name)
Definition: LibCxxUnorderedMap.cpp:90