LLDB  mainline
NSIndexPath.cpp
Go to the documentation of this file.
1 //===-- NSIndexPath.cpp -----------------------------------------*- C++ -*-===//
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 "Cocoa.h"
10 
11 #include "lldb/Core/ValueObject.h"
17 #include "lldb/Target/Process.h"
18 #include "lldb/Target/Target.h"
19 
20 using namespace lldb;
21 using namespace lldb_private;
22 using namespace lldb_private::formatters;
23 
24 static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i) {
25  return (60 - (13 * (4 - i)));
26 }
27 
28 static constexpr size_t PACKED_INDEX_SHIFT_32(size_t i) {
29  return (32 - (13 * (2 - i)));
30 }
31 
33 public:
34  NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
35  : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_descriptor_sp(nullptr),
36  m_impl(), m_ptr_size(0), m_uint_star_type() {
37  m_ptr_size =
38  m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize();
39  }
40 
41  ~NSIndexPathSyntheticFrontEnd() override = default;
42 
43  size_t CalculateNumChildren() override { return m_impl.GetNumIndexes(); }
44 
45  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
46  return m_impl.GetIndexAtIndex(idx, m_uint_star_type);
47  }
48 
49  bool Update() override {
50  m_impl.Clear();
51 
52  TypeSystem *type_system = m_backend.GetCompilerType().GetTypeSystem();
53  if (!type_system)
54  return false;
55 
56  ClangASTContext *ast = m_backend.GetExecutionContextRef()
57  .GetTargetSP()
58  ->GetScratchClangASTContext();
59  if (!ast)
60  return false;
61 
62  m_uint_star_type = ast->GetPointerSizedIntType(false);
63 
64  static ConstString g__indexes("_indexes");
65  static ConstString g__length("_length");
66 
67  ProcessSP process_sp = m_backend.GetProcessSP();
68  if (!process_sp)
69  return false;
70 
71  ObjCLanguageRuntime *runtime =
72  (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
74 
75  if (!runtime)
76  return false;
77 
79  runtime->GetClassDescriptor(m_backend));
80 
81  if (!descriptor.get() || !descriptor->IsValid())
82  return false;
83 
84  uint64_t info_bits(0), value_bits(0), payload(0);
85 
86  if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload)) {
87  m_impl.m_inlined.SetIndexes(payload, *process_sp);
88  m_impl.m_mode = Mode::Inlined;
89  } else {
92 
93  bool has_indexes(false), has_length(false);
94 
95  for (size_t x = 0; x < descriptor->GetNumIVars(); x++) {
96  const auto &ivar = descriptor->GetIVarAtIndex(x);
97  if (ivar.m_name == g__indexes) {
98  _indexes_id = ivar;
99  has_indexes = true;
100  } else if (ivar.m_name == g__length) {
101  _length_id = ivar;
102  has_length = true;
103  }
104 
105  if (has_length && has_indexes)
106  break;
107  }
108 
109  if (has_length && has_indexes) {
110  m_impl.m_outsourced.m_indexes =
111  m_backend
112  .GetSyntheticChildAtOffset(_indexes_id.m_offset,
113  m_uint_star_type.GetPointerType(),
114  true)
115  .get();
116  ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(
117  _length_id.m_offset, m_uint_star_type, true));
118  if (length_sp) {
119  m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);
120  if (m_impl.m_outsourced.m_indexes)
121  m_impl.m_mode = Mode::Outsourced;
122  }
123  }
124  }
125  return false;
126  }
127 
128  bool MightHaveChildren() override { return m_impl.m_mode != Mode::Invalid; }
129 
130  size_t GetIndexOfChildWithName(ConstString name) override {
131  const char *item_name = name.GetCString();
132  uint32_t idx = ExtractIndexFromString(item_name);
133  if (idx < UINT32_MAX && idx >= CalculateNumChildren())
134  return UINT32_MAX;
135  return idx;
136  }
137 
138  lldb::ValueObjectSP GetSyntheticValue() override { return nullptr; }
139 
140 protected:
142 
143  enum class Mode { Inlined, Outsourced, Invalid };
144 
145  struct Impl {
146  size_t GetNumIndexes() {
147  switch (m_mode) {
148  case Mode::Inlined:
149  return m_inlined.GetNumIndexes();
150  case Mode::Outsourced:
151  return m_outsourced.m_count;
152  default:
153  return 0;
154  }
155  }
156 
157  lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
158  const CompilerType &desired_type) {
159  if (idx >= GetNumIndexes())
160  return nullptr;
161  switch (m_mode) {
162  default:
163  return nullptr;
164  case Mode::Inlined:
165  return m_inlined.GetIndexAtIndex(idx, desired_type);
166  case Mode::Outsourced:
167  return m_outsourced.GetIndexAtIndex(idx);
168  }
169  }
170 
171  struct InlinedIndexes {
172  public:
173  void SetIndexes(uint64_t value, Process &p) {
174  m_indexes = value;
175  _lengthForInlinePayload(p.GetAddressByteSize());
176  m_process = &p;
177  }
178 
179  size_t GetNumIndexes() { return m_count; }
180 
181  lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
182  const CompilerType &desired_type) {
183  if (!m_process)
184  return nullptr;
185 
186  std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
187  if (!value.second)
188  return nullptr;
189 
190  Value v;
191  if (m_ptr_size == 8) {
192  Scalar scalar((unsigned long long)value.first);
193  v = Value(scalar);
194  } else {
195  Scalar scalar((unsigned int)value.first);
196  v = Value(scalar);
197  }
198 
199  v.SetCompilerType(desired_type);
200 
201  StreamString idx_name;
202  idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
203 
204  return ValueObjectConstResult::Create(
205  m_process, v, ConstString(idx_name.GetString()));
206  }
207 
208  void Clear() {
209  m_indexes = 0;
210  m_count = 0;
211  m_ptr_size = 0;
212  m_process = nullptr;
213  }
214 
216  : m_indexes(0), m_count(0), m_ptr_size(0), m_process(nullptr) {}
217 
218  private:
219  uint64_t m_indexes;
220  size_t m_count;
221  uint32_t m_ptr_size;
222  Process *m_process;
223 
224  // cfr. Foundation for the details of this code
225  size_t _lengthForInlinePayload(uint32_t ptr_size) {
226  m_ptr_size = ptr_size;
227  if (m_ptr_size == 8)
228  m_count = ((m_indexes >> 3) & 0x7);
229  else
230  m_count = ((m_indexes >> 3) & 0x3);
231  return m_count;
232  }
233 
234  std::pair<uint64_t, bool> _indexAtPositionForInlinePayload(size_t pos) {
235  static const uint64_t PACKED_INDEX_MASK = ((1 << 13) - 1);
236  if (m_ptr_size == 8) {
237  switch (pos) {
238  case 3:
239  case 2:
240  case 1:
241  case 0:
242  return {(m_indexes >> PACKED_INDEX_SHIFT_64(pos)) &
243  PACKED_INDEX_MASK,
244  true};
245  default:
246  return {0, false};
247  }
248  } else {
249  switch (pos) {
250  case 0:
251  case 1:
252  return {(m_indexes >> PACKED_INDEX_SHIFT_32(pos)) &
253  PACKED_INDEX_MASK,
254  true};
255  default:
256  return {0, false};
257  }
258  }
259  return {0, false};
260  }
261  };
262 
264  lldb::ValueObjectSP GetIndexAtIndex(size_t idx) {
265  if (m_indexes) {
266  ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
267  return index_sp;
268  }
269  return nullptr;
270  }
271 
272  void Clear() {
273  m_indexes = nullptr;
274  m_count = 0;
275  }
276 
277  OutsourcedIndexes() : m_indexes(nullptr), m_count(0) {}
278 
280  size_t m_count;
281  };
282 
283  union {
284  struct InlinedIndexes m_inlined;
285  struct OutsourcedIndexes m_outsourced;
286  };
287 
288  void Clear() {
289  m_mode = Mode::Invalid;
290  m_inlined.Clear();
291  m_outsourced.Clear();
292  }
293 
294  Impl() : m_mode(Mode::Invalid) {}
295 
297  } m_impl;
298 
301 };
302 
303 namespace lldb_private {
304 namespace formatters {
305 
308  lldb::ValueObjectSP valobj_sp) {
309  if (valobj_sp)
310  return new NSIndexPathSyntheticFrontEnd(valobj_sp);
311  return nullptr;
312 }
313 
314 } // namespace formatters
315 } // namespace lldb_private
void SetIndexes(uint64_t value, Process &p)
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp
lldb::ValueObjectSP GetIndexAtIndex(size_t idx, const CompilerType &desired_type)
size_t GetIndexOfChildWithName(ConstString name) override
static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i)
Definition: NSIndexPath.cpp:24
std::shared_ptr< ClassDescriptor > ClassDescriptorSP
size_t ExtractIndexFromString(const char *item_name)
#define UINT32_MAX
Definition: lldb-defines.h:31
lldb::ValueObjectSP GetIndexAtIndex(size_t idx, const CompilerType &desired_type)
CompilerType GetPointerSizedIntType(bool is_signed)
static constexpr size_t PACKED_INDEX_SHIFT_32(size_t i)
Definition: NSIndexPath.cpp:28
uint32_t GetAddressByteSize() const
Definition: Process.cpp:3370
llvm::StringRef GetString() const
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
Definition: NSIndexPath.cpp:45
A plug-in interface definition class for debugging a process.
Definition: Process.h:353
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
lldb::ValueObjectSP GetSyntheticValue() override
bool MightHaveChildren() override
static size_t CalculateNumChildren(CompilerType container_type, CompilerType element_type, lldb_private::ExecutionContextScope *exe_scope=nullptr)
Definition: VectorType.cpp:168
NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
Definition: NSIndexPath.cpp:34
A uniqued constant string class.
Definition: ConstString.h:38
const char * GetCString() const
Get the string value as a C string.
Definition: ConstString.h:247
Definition: SBAddress.h:15
virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value)
void SetCompilerType(const CompilerType &compiler_type)
Definition: Value.cpp:268
size_t CalculateNumChildren() override
Definition: NSIndexPath.cpp:43
SyntheticChildrenFrontEnd * NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)