Coverage Report

Created: 2023-09-21 18:56

/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
40
static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i) {
25
40
  return (60 - (13 * (4 - i)));
26
40
}
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
40
      : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_descriptor_sp(nullptr),
36
40
        m_impl(), m_uint_star_type() {
37
40
    m_ptr_size =
38
40
        m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize();
39
40
  }
40
41
40
  ~NSIndexPathSyntheticFrontEnd() override = default;
42
43
20
  size_t CalculateNumChildren() override { return m_impl.GetNumIndexes(); }
44
45
60
  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
46
60
    return m_impl.GetIndexAtIndex(idx, m_uint_star_type);
47
60
  }
48
49
20
  bool Update() override {
50
20
    m_impl.Clear();
51
52
20
    auto type_system = m_backend.GetCompilerType().GetTypeSystem();
53
20
    if (!type_system)
54
0
      return false;
55
56
20
    auto ast = ScratchTypeSystemClang::GetForTarget(
57
20
        *m_backend.GetExecutionContextRef().GetTargetSP());
58
20
    if (!ast)
59
0
      return false;
60
61
20
    m_uint_star_type = ast->GetPointerSizedIntType(false);
62
63
20
    static ConstString g__indexes("_indexes");
64
20
    static ConstString g__length("_length");
65
66
20
    ProcessSP process_sp = m_backend.GetProcessSP();
67
20
    if (!process_sp)
68
0
      return false;
69
70
20
    ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
71
72
20
    if (!runtime)
73
0
      return false;
74
75
20
    ObjCLanguageRuntime::ClassDescriptorSP descriptor(
76
20
        runtime->GetClassDescriptor(m_backend));
77
78
20
    if (!descriptor.get() || !descriptor->IsValid())
79
0
      return false;
80
81
20
    uint64_t info_bits(0), value_bits(0), payload(0);
82
83
20
    if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload)) {
84
16
      m_impl.m_inlined.SetIndexes(payload, *process_sp);
85
16
      m_impl.m_mode = Mode::Inlined;
86
16
    } else {
87
4
      ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id;
88
4
      ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id;
89
90
4
      bool has_indexes(false), has_length(false);
91
92
8
      for (size_t x = 0; x < descriptor->GetNumIVars(); 
x++4
) {
93
8
        const auto &ivar = descriptor->GetIVarAtIndex(x);
94
8
        if (ivar.m_name == g__indexes) {
95
4
          _indexes_id = ivar;
96
4
          has_indexes = true;
97
4
        } else if (ivar.m_name == g__length) {
98
4
          _length_id = ivar;
99
4
          has_length = true;
100
4
        }
101
102
8
        if (has_length && 
has_indexes4
)
103
4
          break;
104
8
      }
105
106
4
      if (has_length && has_indexes) {
107
4
        m_impl.m_outsourced.m_indexes =
108
4
            m_backend
109
4
                .GetSyntheticChildAtOffset(_indexes_id.m_offset,
110
4
                                           m_uint_star_type.GetPointerType(),
111
4
                                           true)
112
4
                .get();
113
4
        ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(
114
4
            _length_id.m_offset, m_uint_star_type, true));
115
4
        if (length_sp) {
116
4
          m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);
117
4
          if (m_impl.m_outsourced.m_indexes)
118
4
            m_impl.m_mode = Mode::Outsourced;
119
4
        }
120
4
      }
121
4
    }
122
20
    return false;
123
20
  }
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
20
  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
80
    size_t GetNumIndexes() {
144
80
      switch (m_mode) {
145
56
      case Mode::Inlined:
146
56
        return m_inlined.GetNumIndexes();
147
24
      case Mode::Outsourced:
148
24
        return m_outsourced.m_count;
149
0
      default:
150
0
        return 0;
151
80
      }
152
80
    }
153
154
    lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
155
60
                                        const CompilerType &desired_type) {
156
60
      if (idx >= GetNumIndexes())
157
0
        return nullptr;
158
60
      switch (m_mode) {
159
0
      default:
160
0
        return nullptr;
161
40
      case Mode::Inlined:
162
40
        return m_inlined.GetIndexAtIndex(idx, desired_type);
163
20
      case Mode::Outsourced:
164
20
        return m_outsourced.GetIndexAtIndex(idx);
165
60
      }
166
60
    }
167
168
    struct InlinedIndexes {
169
    public:
170
16
      void SetIndexes(uint64_t value, Process &p) {
171
16
        m_indexes = value;
172
16
        _lengthForInlinePayload(p.GetAddressByteSize());
173
16
        m_process = &p;
174
16
      }
175
176
56
      size_t GetNumIndexes() { return m_count; }
177
178
      lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
179
40
                                          const CompilerType &desired_type) {
180
40
        if (!m_process)
181
0
          return nullptr;
182
183
40
        std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
184
40
        if (!value.second)
185
0
          return nullptr;
186
187
40
        Value v;
188
40
        if (m_ptr_size == 8) {
189
40
          Scalar scalar((unsigned long long)value.first);
190
40
          v = Value(scalar);
191
40
        } else {
192
0
          Scalar scalar((unsigned int)value.first);
193
0
          v = Value(scalar);
194
0
        }
195
196
40
        v.SetCompilerType(desired_type);
197
198
40
        StreamString idx_name;
199
40
        idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
200
201
40
        return ValueObjectConstResult::Create(
202
40
            m_process, v, ConstString(idx_name.GetString()));
203
40
      }
204
205
0
      void Clear() {
206
0
        m_indexes = 0;
207
0
        m_count = 0;
208
0
        m_ptr_size = 0;
209
0
        m_process = nullptr;
210
0
      }
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
16
      size_t _lengthForInlinePayload(uint32_t ptr_size) {
222
16
        m_ptr_size = ptr_size;
223
16
        if (m_ptr_size == 8)
224
16
          m_count = ((m_indexes >> 3) & 0x7);
225
0
        else
226
0
          m_count = ((m_indexes >> 3) & 0x3);
227
16
        return m_count;
228
16
      }
229
230
40
      std::pair<uint64_t, bool> _indexAtPositionForInlinePayload(size_t pos) {
231
40
        static const uint64_t PACKED_INDEX_MASK = ((1 << 13) - 1);
232
40
        if (m_ptr_size == 8) {
233
40
          switch (pos) {
234
4
          case 3:
235
12
          case 2:
236
24
          case 1:
237
40
          case 0:
238
40
            return {(m_indexes >> PACKED_INDEX_SHIFT_64(pos)) &
239
40
                        PACKED_INDEX_MASK,
240
40
                    true};
241
0
          default:
242
0
            return {0, false};
243
40
          }
244
40
        } 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
40
      }
257
    };
258
259
    struct OutsourcedIndexes {
260
20
      lldb::ValueObjectSP GetIndexAtIndex(size_t idx) {
261
20
        if (m_indexes) {
262
20
          ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
263
20
          return index_sp;
264
20
        }
265
0
        return nullptr;
266
20
      }
267
268
0
      void Clear() {
269
0
        m_indexes = nullptr;
270
0
        m_count = 0;
271
0
      }
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
20
    void Clear() {
285
20
      switch (m_mode) {
286
0
      case Mode::Inlined:
287
0
        m_inlined.Clear();
288
0
        break;
289
0
      case Mode::Outsourced:
290
0
        m_outsourced.Clear();
291
0
        break;
292
20
      case Mode::Invalid:
293
20
        break;
294
20
      }
295
20
      m_mode = Mode::Invalid;
296
20
    }
297
298
40
    Impl() {}
299
300
    Mode m_mode = Mode::Invalid;
301
  } m_impl;
302
303
  uint32_t m_ptr_size = 0;
304
  CompilerType m_uint_star_type;
305
};
306
307
namespace lldb_private {
308
namespace formatters {
309
310
SyntheticChildrenFrontEnd *
311
NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *,
312
40
                                    lldb::ValueObjectSP valobj_sp) {
313
40
  if (valobj_sp)
314
40
    return new NSIndexPathSyntheticFrontEnd(valobj_sp);
315
0
  return nullptr;
316
40
}
317
318
} // namespace formatters
319
} // namespace lldb_private