Coverage Report

Created: 2022-01-18 06:27

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