Coverage Report

Created: 2023-09-30 09:22

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