Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- GenericBitset.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
#include "LibStdcpp.h"
11
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12
#include "lldb/DataFormatters/FormattersHelpers.h"
13
#include "lldb/Target/Target.h"
14
15
using namespace lldb;
16
using namespace lldb_private;
17
18
namespace {
19
20
/// This class can be used for handling bitsets from both libcxx and libstdcpp.
21
class GenericBitsetFrontEnd : public SyntheticChildrenFrontEnd {
22
public:
23
  enum class StdLib {
24
    LibCxx,
25
    LibStdcpp,
26
  };
27
28
  GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib);
29
30
0
  size_t GetIndexOfChildWithName(ConstString name) override {
31
0
    return formatters::ExtractIndexFromString(name.GetCString());
32
0
  }
33
34
3
  bool MightHaveChildren() override { return true; }
35
  bool Update() override;
36
30
  size_t CalculateNumChildren() override { return m_elements.size(); }
37
  ValueObjectSP GetChildAtIndex(size_t idx) override;
38
39
private:
40
  ConstString GetDataContainerMemberName();
41
42
  // The lifetime of a ValueObject and all its derivative ValueObjects
43
  // (children, clones, etc.) is managed by a ClusterManager. These
44
  // objects are only destroyed when every shared pointer to any of them
45
  // is destroyed, so we must not store a shared pointer to any ValueObject
46
  // derived from our backend ValueObject (since we're in the same cluster).
47
  // Value objects created from raw data (i.e. in a different cluster) must
48
  // be referenced via shared pointer to keep them alive, however.
49
  std::vector<ValueObjectSP> m_elements;
50
  ValueObject *m_first = nullptr;
51
  CompilerType m_bool_type;
52
  ByteOrder m_byte_order = eByteOrderInvalid;
53
  uint8_t m_byte_size = 0;
54
  StdLib m_stdlib;
55
};
56
} // namespace
57
58
GenericBitsetFrontEnd::GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib)
59
30
    : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) {
60
30
  m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool);
61
30
  if (auto target_sp = m_backend.GetTargetSP()) {
62
30
    m_byte_order = target_sp->GetArchitecture().GetByteOrder();
63
30
    m_byte_size = target_sp->GetArchitecture().GetAddressByteSize();
64
30
    Update();
65
30
  }
66
30
}
67
68
60
ConstString GenericBitsetFrontEnd::GetDataContainerMemberName() {
69
60
  switch (m_stdlib) {
70
60
  case StdLib::LibCxx:
71
60
    return ConstString("__first_");
72
0
  case StdLib::LibStdcpp:
73
0
    return ConstString("_M_w");
74
60
  }
75
60
}
76
77
60
bool GenericBitsetFrontEnd::Update() {
78
60
  m_elements.clear();
79
60
  m_first = nullptr;
80
81
60
  TargetSP target_sp = m_backend.GetTargetSP();
82
60
  if (!target_sp)
83
0
    return false;
84
85
60
  size_t size = 0;
86
87
60
  if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(0))
88
60
    size = arg->value.getLimitedValue();
89
90
60
  m_elements.assign(size, ValueObjectSP());
91
60
  m_first = m_backend.GetChildMemberWithName(GetDataContainerMemberName(), true)
92
60
                .get();
93
60
  return false;
94
60
}
95
96
9.74k
ValueObjectSP GenericBitsetFrontEnd::GetChildAtIndex(size_t idx) {
97
9.74k
  if (idx >= m_elements.size() || !m_first)
98
0
    return ValueObjectSP();
99
100
9.74k
  if (m_elements[idx])
101
0
    return m_elements[idx];
102
103
9.74k
  ExecutionContext ctx = m_backend.GetExecutionContextRef().Lock(false);
104
9.74k
  CompilerType type;
105
9.74k
  ValueObjectSP chunk;
106
  // For small bitsets __first_ is not an array, but a plain size_t.
107
9.74k
  if (m_first->GetCompilerType().IsArrayType(&type)) {
108
9.63k
    llvm::Optional<uint64_t> bit_size =
109
9.63k
        type.GetBitSize(ctx.GetBestExecutionContextScope());
110
9.63k
    if (!bit_size || *bit_size == 0)
111
0
      return {};
112
9.63k
    chunk = m_first->GetChildAtIndex(idx / *bit_size, true);
113
9.63k
  } else {
114
117
    type = m_first->GetCompilerType();
115
117
    chunk = m_first->GetSP();
116
117
  }
117
9.74k
  if (!type || !chunk)
118
0
    return {};
119
120
9.74k
  llvm::Optional<uint64_t> bit_size =
121
9.74k
      type.GetBitSize(ctx.GetBestExecutionContextScope());
122
9.74k
  if (!bit_size || *bit_size == 0)
123
0
    return {};
124
9.74k
  size_t chunk_idx = idx % *bit_size;
125
9.74k
  uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx));
126
9.74k
  DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size);
127
128
9.74k
  m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(),
129
9.74k
                                              data, ctx, m_bool_type);
130
131
9.74k
  return m_elements[idx];
132
9.74k
}
133
134
SyntheticChildrenFrontEnd *formatters::LibStdcppBitsetSyntheticFrontEndCreator(
135
0
    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
136
0
  if (valobj_sp)
137
0
    return new GenericBitsetFrontEnd(*valobj_sp,
138
0
                                     GenericBitsetFrontEnd::StdLib::LibStdcpp);
139
0
  return nullptr;
140
0
}
141
142
SyntheticChildrenFrontEnd *formatters::LibcxxBitsetSyntheticFrontEndCreator(
143
30
    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
144
30
  if (valobj_sp)
145
30
    return new GenericBitsetFrontEnd(*valobj_sp,
146
30
                                     GenericBitsetFrontEnd::StdLib::LibCxx);
147
0
  return nullptr;
148
30
}