Coverage Report

Created: 2022-01-22 13:19

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- LibCxxMap.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
11
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12
#include "lldb/Core/ValueObject.h"
13
#include "lldb/Core/ValueObjectConstResult.h"
14
#include "lldb/DataFormatters/FormattersHelpers.h"
15
#include "lldb/Target/Target.h"
16
#include "lldb/Utility/DataBufferHeap.h"
17
#include "lldb/Utility/Endian.h"
18
#include "lldb/Utility/Status.h"
19
#include "lldb/Utility/Stream.h"
20
21
using namespace lldb;
22
using namespace lldb_private;
23
using namespace lldb_private::formatters;
24
25
class MapEntry {
26
public:
27
513
  MapEntry() = default;
28
1.00k
  explicit MapEntry(ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
29
  explicit MapEntry(ValueObject *entry)
30
513
      : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
31
32
489
  ValueObjectSP left() const {
33
489
    static ConstString g_left("__left_");
34
489
    if (!m_entry_sp)
35
0
      return m_entry_sp;
36
489
    return m_entry_sp->GetSyntheticChildAtOffset(
37
489
        0, m_entry_sp->GetCompilerType(), true);
38
489
  }
39
40
402
  ValueObjectSP right() const {
41
402
    static ConstString g_right("__right_");
42
402
    if (!m_entry_sp)
43
0
      return m_entry_sp;
44
402
    return m_entry_sp->GetSyntheticChildAtOffset(
45
402
        m_entry_sp->GetProcessSP()->GetAddressByteSize(),
46
402
        m_entry_sp->GetCompilerType(), true);
47
402
  }
48
49
408
  ValueObjectSP parent() const {
50
408
    static ConstString g_parent("__parent_");
51
408
    if (!m_entry_sp)
52
0
      return m_entry_sp;
53
408
    return m_entry_sp->GetSyntheticChildAtOffset(
54
408
        2 * m_entry_sp->GetProcessSP()->GetAddressByteSize(),
55
408
        m_entry_sp->GetCompilerType(), true);
56
408
  }
57
58
2.32k
  uint64_t value() const {
59
2.32k
    if (!m_entry_sp)
60
0
      return 0;
61
2.32k
    return m_entry_sp->GetValueAsUnsigned(0);
62
2.32k
  }
63
64
87
  bool error() const {
65
87
    if (!m_entry_sp)
66
0
      return true;
67
87
    return m_entry_sp->GetError().Fail();
68
87
  }
69
70
1.92k
  bool null() const { return (value() == 0); }
71
72
513
  ValueObjectSP GetEntry() const { return m_entry_sp; }
73
74
291
  void SetEntry(ValueObjectSP entry) { m_entry_sp = entry; }
75
76
0
  bool operator==(const MapEntry &rhs) const {
77
0
    return (rhs.m_entry_sp.get() == m_entry_sp.get());
78
0
  }
79
80
private:
81
  ValueObjectSP m_entry_sp;
82
};
83
84
class MapIterator {
85
public:
86
513
  MapIterator() = default;
87
  MapIterator(MapEntry entry, size_t depth = 0)
88
0
      : m_entry(std::move(entry)), m_max_depth(depth), m_error(false) {}
89
  MapIterator(ValueObjectSP entry, size_t depth = 0)
90
0
      : m_entry(std::move(entry)), m_max_depth(depth), m_error(false) {}
91
  MapIterator(const MapIterator &rhs)
92
0
      : m_entry(rhs.m_entry), m_max_depth(rhs.m_max_depth), m_error(false) {}
93
  MapIterator(ValueObject *entry, size_t depth = 0)
94
513
      : m_entry(entry), m_max_depth(depth), m_error(false) {}
95
96
894
  MapIterator &operator=(const MapIterator &) = default;
97
98
0
  ValueObjectSP value() { return m_entry.GetEntry(); }
99
100
513
  ValueObjectSP advance(size_t count) {
101
513
    ValueObjectSP fail;
102
513
    if (m_error)
103
0
      return fail;
104
513
    size_t steps = 0;
105
915
    while (count > 0) {
106
402
      next();
107
402
      count--, steps++;
108
402
      if (m_error || m_entry.null() || (steps > m_max_depth))
109
0
        return fail;
110
402
    }
111
513
    return m_entry.GetEntry();
112
513
  }
113
114
protected:
115
402
  void next() {
116
402
    if (m_entry.null())
117
0
      return;
118
402
    MapEntry right(m_entry.right());
119
402
    if (!right.null()) {
120
225
      m_entry = tree_min(std::move(right));
121
225
      return;
122
225
    }
123
177
    size_t steps = 0;
124
204
    while (!is_left_child(m_entry)) {
125
27
      if (m_entry.error()) {
126
0
        m_error = true;
127
0
        return;
128
0
      }
129
27
      m_entry.SetEntry(m_entry.parent());
130
27
      steps++;
131
27
      if (steps > m_max_depth) {
132
0
        m_entry = MapEntry();
133
0
        return;
134
0
      }
135
27
    }
136
177
    m_entry = MapEntry(m_entry.parent());
137
177
  }
138
139
private:
140
225
  MapEntry tree_min(MapEntry x) {
141
225
    if (x.null())
142
0
      return MapEntry();
143
225
    MapEntry left(x.left());
144
225
    size_t steps = 0;
145
285
    while (!left.null()) {
146
60
      if (left.error()) {
147
0
        m_error = true;
148
0
        return MapEntry();
149
0
      }
150
60
      x = left;
151
60
      left.SetEntry(x.left());
152
60
      steps++;
153
60
      if (steps > m_max_depth)
154
0
        return MapEntry();
155
60
    }
156
225
    return x;
157
225
  }
158
159
204
  bool is_left_child(const MapEntry &x) {
160
204
    if (x.null())
161
0
      return false;
162
204
    MapEntry rhs(x.parent());
163
204
    rhs.SetEntry(rhs.left());
164
204
    return x.value() == rhs.value();
165
204
  }
166
167
  MapEntry m_entry;
168
  size_t m_max_depth;
169
  bool m_error;
170
};
171
172
namespace lldb_private {
173
namespace formatters {
174
class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
175
public:
176
  LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
177
178
90
  ~LibcxxStdMapSyntheticFrontEnd() override = default;
179
180
  size_t CalculateNumChildren() override;
181
182
  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
183
184
  bool Update() override;
185
186
  bool MightHaveChildren() override;
187
188
  size_t GetIndexOfChildWithName(ConstString name) override;
189
190
private:
191
  bool GetDataType();
192
193
  void GetValueOffset(const lldb::ValueObjectSP &node);
194
195
  ValueObject *m_tree;
196
  ValueObject *m_root_node;
197
  CompilerType m_element_type;
198
  uint32_t m_skip_size;
199
  size_t m_count;
200
  std::map<size_t, MapIterator> m_iterators;
201
};
202
} // namespace formatters
203
} // namespace lldb_private
204
205
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
206
    LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
207
    : SyntheticChildrenFrontEnd(*valobj_sp), m_tree(nullptr),
208
      m_root_node(nullptr), m_element_type(), m_skip_size(UINT32_MAX),
209
213
      m_count(UINT32_MAX), m_iterators() {
210
213
  if (valobj_sp)
211
213
    Update();
212
213
}
213
214
size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
215
1.23k
    CalculateNumChildren() {
216
1.23k
  static ConstString g___pair3_("__pair3_");
217
1.23k
  static ConstString g___first_("__first_");
218
1.23k
  static ConstString g___value_("__value_");
219
220
1.23k
  if (m_count != UINT32_MAX)
221
1.02k
    return m_count;
222
213
  if (m_tree == nullptr)
223
0
    return 0;
224
213
  ValueObjectSP m_item(m_tree->GetChildMemberWithName(g___pair3_, true));
225
213
  if (!m_item)
226
0
    return 0;
227
228
213
  switch (m_item->GetCompilerType().GetNumDirectBaseClasses()) {
229
0
  case 1:
230
    // Assume a pre llvm r300140 __compressed_pair implementation:
231
0
    m_item = m_item->GetChildMemberWithName(g___first_, true);
232
0
    break;
233
213
  case 2: {
234
    // Assume a post llvm r300140 __compressed_pair implementation:
235
213
    ValueObjectSP first_elem_parent = m_item->GetChildAtIndex(0, true);
236
213
    m_item = first_elem_parent->GetChildMemberWithName(g___value_, true);
237
213
    break;
238
0
  }
239
0
  default:
240
0
    return false;
241
213
  }
242
243
213
  if (!m_item)
244
0
    return 0;
245
213
  m_count = m_item->GetValueAsUnsigned(0);
246
213
  return m_count;
247
213
}
248
249
513
bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType() {
250
513
  static ConstString g___value_("__value_");
251
513
  static ConstString g_tree_("__tree_");
252
513
  static ConstString g_pair3("__pair3_");
253
254
513
  if (m_element_type.GetOpaqueQualType() && 
m_element_type.GetTypeSystem()390
)
255
390
    return true;
256
123
  m_element_type.Clear();
257
123
  ValueObjectSP deref;
258
123
  Status error;
259
123
  deref = m_root_node->Dereference(error);
260
123
  if (!deref || error.Fail())
261
0
    return false;
262
123
  deref = deref->GetChildMemberWithName(g___value_, true);
263
123
  if (deref) {
264
0
    m_element_type = deref->GetCompilerType();
265
0
    return true;
266
0
  }
267
123
  deref = m_backend.GetChildAtNamePath({g_tree_, g_pair3});
268
123
  if (!deref)
269
0
    return false;
270
123
  m_element_type = deref->GetCompilerType()
271
123
                       .GetTypeTemplateArgument(1)
272
123
                       .GetTypeTemplateArgument(1);
273
123
  if (m_element_type) {
274
72
    std::string name;
275
72
    uint64_t bit_offset_ptr;
276
72
    uint32_t bitfield_bit_size_ptr;
277
72
    bool is_bitfield_ptr;
278
72
    m_element_type = m_element_type.GetFieldAtIndex(
279
72
        0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
280
72
    m_element_type = m_element_type.GetTypedefedType();
281
72
    return m_element_type.IsValid();
282
72
  } else {
283
51
    m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0);
284
51
    return m_element_type.IsValid();
285
51
  }
286
123
}
287
288
void lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset(
289
123
    const lldb::ValueObjectSP &node) {
290
123
  if (m_skip_size != UINT32_MAX)
291
0
    return;
292
123
  if (!node)
293
0
    return;
294
123
  CompilerType node_type(node->GetCompilerType());
295
123
  uint64_t bit_offset;
296
123
  if (node_type.GetIndexOfFieldWithName("__value_", nullptr, &bit_offset) !=
297
123
      UINT32_MAX) {
298
0
    m_skip_size = bit_offset / 8u;
299
123
  } else {
300
123
    TypeSystemClang *ast_ctx =
301
123
        llvm::dyn_cast_or_null<TypeSystemClang>(node_type.GetTypeSystem());
302
123
    if (!ast_ctx)
303
0
      return;
304
123
    CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(
305
123
        ConstString(),
306
123
        {{"ptr0", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
307
123
         {"ptr1", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
308
123
         {"ptr2", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
309
123
         {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)},
310
123
         {"payload", (m_element_type.GetCompleteType(), m_element_type)}});
311
123
    std::string child_name;
312
123
    uint32_t child_byte_size;
313
123
    int32_t child_byte_offset = 0;
314
123
    uint32_t child_bitfield_bit_size;
315
123
    uint32_t child_bitfield_bit_offset;
316
123
    bool child_is_base_class;
317
123
    bool child_is_deref_of_parent;
318
123
    uint64_t language_flags;
319
123
    if (tree_node_type
320
123
            .GetChildCompilerTypeAtIndex(
321
123
                nullptr, 4, true, true, true, child_name, child_byte_size,
322
123
                child_byte_offset, child_bitfield_bit_size,
323
123
                child_bitfield_bit_offset, child_is_base_class,
324
123
                child_is_deref_of_parent, nullptr, language_flags)
325
123
            .IsValid())
326
123
      m_skip_size = (uint32_t)child_byte_offset;
327
123
  }
328
123
}
329
330
lldb::ValueObjectSP
331
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex(
332
513
    size_t idx) {
333
513
  static ConstString g___cc("__cc");
334
513
  static ConstString g___nc("__nc");
335
513
  static ConstString g___value_("__value_");
336
337
513
  if (idx >= CalculateNumChildren())
338
0
    return lldb::ValueObjectSP();
339
513
  if (m_tree == nullptr || m_root_node == nullptr)
340
0
    return lldb::ValueObjectSP();
341
342
513
  MapIterator iterator(m_root_node, CalculateNumChildren());
343
344
513
  const bool need_to_skip = (idx > 0);
345
513
  size_t actual_advancde = idx;
346
513
  if (need_to_skip) {
347
390
    auto cached_iterator = m_iterators.find(idx - 1);
348
390
    if (cached_iterator != m_iterators.end()) {
349
381
      iterator = cached_iterator->second;
350
381
      actual_advancde = 1;
351
381
    }
352
390
  }
353
354
513
  ValueObjectSP iterated_sp(iterator.advance(actual_advancde));
355
513
  if (!iterated_sp) {
356
    // this tree is garbage - stop
357
0
    m_tree =
358
0
        nullptr; // this will stop all future searches until an Update() happens
359
0
    return iterated_sp;
360
0
  }
361
513
  if (GetDataType()) {
362
513
    if (!need_to_skip) {
363
123
      Status error;
364
123
      iterated_sp = iterated_sp->Dereference(error);
365
123
      if (!iterated_sp || error.Fail()) {
366
0
        m_tree = nullptr;
367
0
        return lldb::ValueObjectSP();
368
0
      }
369
123
      GetValueOffset(iterated_sp);
370
123
      auto child_sp = iterated_sp->GetChildMemberWithName(g___value_, true);
371
123
      if (child_sp)
372
0
        iterated_sp = child_sp;
373
123
      else
374
123
        iterated_sp = iterated_sp->GetSyntheticChildAtOffset(
375
123
            m_skip_size, m_element_type, true);
376
123
      if (!iterated_sp) {
377
0
        m_tree = nullptr;
378
0
        return lldb::ValueObjectSP();
379
0
      }
380
390
    } else {
381
      // because of the way our debug info is made, we need to read item 0
382
      // first so that we can cache information used to generate other elements
383
390
      if (m_skip_size == UINT32_MAX)
384
6
        GetChildAtIndex(0);
385
390
      if (m_skip_size == UINT32_MAX) {
386
0
        m_tree = nullptr;
387
0
        return lldb::ValueObjectSP();
388
0
      }
389
390
      iterated_sp = iterated_sp->GetSyntheticChildAtOffset(
390
390
          m_skip_size, m_element_type, true);
391
390
      if (!iterated_sp) {
392
0
        m_tree = nullptr;
393
0
        return lldb::ValueObjectSP();
394
0
      }
395
390
    }
396
513
  } else {
397
0
    m_tree = nullptr;
398
0
    return lldb::ValueObjectSP();
399
0
  }
400
  // at this point we have a valid
401
  // we need to copy current_sp into a new object otherwise we will end up with
402
  // all items named __value_
403
513
  DataExtractor data;
404
513
  Status error;
405
513
  iterated_sp->GetData(data, error);
406
513
  if (error.Fail()) {
407
0
    m_tree = nullptr;
408
0
    return lldb::ValueObjectSP();
409
0
  }
410
513
  StreamString name;
411
513
  name.Printf("[%" PRIu64 "]", (uint64_t)idx);
412
513
  auto potential_child_sp = CreateValueObjectFromData(
413
513
      name.GetString(), data, m_backend.GetExecutionContextRef(),
414
513
      m_element_type);
415
513
  if (potential_child_sp) {
416
513
    switch (potential_child_sp->GetNumChildren()) {
417
90
    case 1: {
418
90
      auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
419
90
      if (child0_sp && child0_sp->GetName() == g___cc)
420
0
        potential_child_sp = child0_sp->Clone(ConstString(name.GetString()));
421
90
      break;
422
0
    }
423
282
    case 2: {
424
282
      auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
425
282
      auto child1_sp = potential_child_sp->GetChildAtIndex(1, true);
426
282
      if (child0_sp && child0_sp->GetName() == g___cc && 
child1_sp0
&&
427
282
          
child1_sp->GetName() == g___nc0
)
428
0
        potential_child_sp = child0_sp->Clone(ConstString(name.GetString()));
429
282
      break;
430
0
    }
431
513
    }
432
513
  }
433
513
  m_iterators[idx] = iterator;
434
513
  return potential_child_sp;
435
513
}
436
437
426
bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() {
438
426
  static ConstString g___tree_("__tree_");
439
426
  static ConstString g___begin_node_("__begin_node_");
440
426
  m_count = UINT32_MAX;
441
426
  m_tree = m_root_node = nullptr;
442
426
  m_iterators.clear();
443
426
  m_tree = m_backend.GetChildMemberWithName(g___tree_, true).get();
444
426
  if (!m_tree)
445
0
    return false;
446
426
  m_root_node = m_tree->GetChildMemberWithName(g___begin_node_, true).get();
447
426
  return false;
448
426
}
449
450
bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
451
102
    MightHaveChildren() {
452
102
  return true;
453
102
}
454
455
size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
456
0
    GetIndexOfChildWithName(ConstString name) {
457
0
  return ExtractIndexFromString(name.GetCString());
458
0
}
459
460
SyntheticChildrenFrontEnd *
461
lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator(
462
213
    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
463
213
  return (valobj_sp ? new LibcxxStdMapSyntheticFrontEnd(valobj_sp) : 
nullptr0
);
464
213
}