Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- TypeIndexDiscovery.cpp -----------------------------------*- C++ -*-===//
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
#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
9
10
#include "llvm/ADT/ArrayRef.h"
11
#include "llvm/Support/Endian.h"
12
13
using namespace llvm;
14
using namespace llvm::codeview;
15
16
1.14k
static inline MethodKind getMethodKind(uint16_t Attrs) {
17
1.14k
  Attrs &= uint16_t(MethodOptions::MethodKindMask);
18
1.14k
  Attrs >>= 2;
19
1.14k
  return MethodKind(Attrs);
20
1.14k
}
21
22
1.14k
static inline bool isIntroVirtual(uint16_t Attrs) {
23
1.14k
  MethodKind MK = getMethodKind(Attrs);
24
1.14k
  return MK == MethodKind::IntroducingVirtual ||
25
1.14k
         
MK == MethodKind::PureIntroducingVirtual1.10k
;
26
1.14k
}
27
28
1.24k
static inline PointerMode getPointerMode(uint32_t Attrs) {
29
1.24k
  return static_cast<PointerMode>((Attrs >> PointerRecord::PointerModeShift) &
30
1.24k
                                  PointerRecord::PointerModeMask);
31
1.24k
}
32
33
1.24k
static inline bool isMemberPointer(uint32_t Attrs) {
34
1.24k
  PointerMode Mode = getPointerMode(Attrs);
35
1.24k
  return Mode == PointerMode::PointerToDataMember ||
36
1.24k
         
Mode == PointerMode::PointerToMemberFunction1.22k
;
37
1.24k
}
38
39
13.5k
static inline uint32_t getEncodedIntegerLength(ArrayRef<uint8_t> Data) {
40
13.5k
  uint16_t N = support::endian::read16le(Data.data());
41
13.5k
  if (N < LF_NUMERIC)
42
13.3k
    return 2;
43
187
44
187
  assert(N <= LF_UQUADWORD);
45
187
46
187
  constexpr uint32_t Sizes[] = {
47
187
      1,  // LF_CHAR
48
187
      2,  // LF_SHORT
49
187
      2,  // LF_USHORT
50
187
      4,  // LF_LONG
51
187
      4,  // LF_ULONG
52
187
      4,  // LF_REAL32
53
187
      8,  // LF_REAL64
54
187
      10, // LF_REAL80
55
187
      16, // LF_REAL128
56
187
      8,  // LF_QUADWORD
57
187
      8,  // LF_UQUADWORD
58
187
  };
59
187
60
187
  return 2 + Sizes[N - LF_NUMERIC];
61
187
}
62
63
14.5k
static inline uint32_t getCStringLength(ArrayRef<uint8_t> Data) {
64
14.5k
  const char *S = reinterpret_cast<const char *>(Data.data());
65
14.5k
  return strlen(S) + 1;
66
14.5k
}
67
68
static void handleMethodOverloadList(ArrayRef<uint8_t> Content,
69
231
                                     SmallVectorImpl<TiReference> &Refs) {
70
231
  uint32_t Offset = 0;
71
231
72
814
  while (!Content.empty()) {
73
583
    // Array of:
74
583
    //   0: Attrs
75
583
    //   2: Padding
76
583
    //   4: TypeIndex
77
583
    //   if (isIntroVirtual())
78
583
    //     8: VFTableOffset
79
583
80
583
    // At least 8 bytes are guaranteed.  4 extra bytes come iff function is an
81
583
    // intro virtual.
82
583
    uint32_t Len = 8;
83
583
84
583
    uint16_t Attrs = support::endian::read16le(Content.data());
85
583
    Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
86
583
87
583
    if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
88
583
      
Len += 44
;
89
583
    Offset += Len;
90
583
    Content = Content.drop_front(Len);
91
583
  }
92
231
}
93
94
static uint32_t handleBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset,
95
42
                                SmallVectorImpl<TiReference> &Refs) {
96
42
  // 0: Kind
97
42
  // 2: Padding
98
42
  // 4: TypeIndex
99
42
  // 8: Encoded Integer
100
42
  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
101
42
  return 8 + getEncodedIntegerLength(Data.drop_front(8));
102
42
}
103
104
static uint32_t handleEnumerator(ArrayRef<uint8_t> Data, uint32_t Offset,
105
12.1k
                                 SmallVectorImpl<TiReference> &Refs) {
106
12.1k
  // 0: Kind
107
12.1k
  // 2: Padding
108
12.1k
  // 4: Encoded Integer
109
12.1k
  // <next>: Name
110
12.1k
  uint32_t Size = 4 + getEncodedIntegerLength(Data.drop_front(4));
111
12.1k
  return Size + getCStringLength(Data.drop_front(Size));
112
12.1k
}
113
114
static uint32_t handleDataMember(ArrayRef<uint8_t> Data, uint32_t Offset,
115
1.28k
                                 SmallVectorImpl<TiReference> &Refs) {
116
1.28k
  // 0: Kind
117
1.28k
  // 2: Padding
118
1.28k
  // 4: TypeIndex
119
1.28k
  // 8: Encoded Integer
120
1.28k
  // <next>: Name
121
1.28k
  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
122
1.28k
  uint32_t Size = 8 + getEncodedIntegerLength(Data.drop_front(8));
123
1.28k
  return Size + getCStringLength(Data.drop_front(Size));
124
1.28k
}
125
126
static uint32_t handleOverloadedMethod(ArrayRef<uint8_t> Data, uint32_t Offset,
127
231
                                       SmallVectorImpl<TiReference> &Refs) {
128
231
  // 0: Kind
129
231
  // 2: Padding
130
231
  // 4: TypeIndex
131
231
  // 8: Name
132
231
  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
133
231
  return 8 + getCStringLength(Data.drop_front(8));
134
231
}
135
136
static uint32_t handleOneMethod(ArrayRef<uint8_t> Data, uint32_t Offset,
137
557
                                SmallVectorImpl<TiReference> &Refs) {
138
557
  // 0: Kind
139
557
  // 2: Attributes
140
557
  // 4: Type
141
557
  // if (isIntroVirtual)
142
557
  //   8: VFTableOffset
143
557
  // <next>: Name
144
557
  uint32_t Size = 8;
145
557
  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
146
557
147
557
  uint16_t Attrs = support::endian::read16le(Data.drop_front(2).data());
148
557
  if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
149
557
    
Size += 436
;
150
557
151
557
  return Size + getCStringLength(Data.drop_front(Size));
152
557
}
153
154
static uint32_t handleNestedType(ArrayRef<uint8_t> Data, uint32_t Offset,
155
140
                                 SmallVectorImpl<TiReference> &Refs) {
156
140
  // 0: Kind
157
140
  // 2: Padding
158
140
  // 4: TypeIndex
159
140
  // 8: Name
160
140
  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
161
140
  return 8 + getCStringLength(Data.drop_front(8));
162
140
}
163
164
static uint32_t handleStaticDataMember(ArrayRef<uint8_t> Data, uint32_t Offset,
165
168
                                       SmallVectorImpl<TiReference> &Refs) {
166
168
  // 0: Kind
167
168
  // 2: Padding
168
168
  // 4: TypeIndex
169
168
  // 8: Name
170
168
  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
171
168
  return 8 + getCStringLength(Data.drop_front(8));
172
168
}
173
174
static uint32_t handleVirtualBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset,
175
                                       bool IsIndirect,
176
24
                                       SmallVectorImpl<TiReference> &Refs) {
177
24
  // 0: Kind
178
24
  // 2: Attrs
179
24
  // 4: TypeIndex
180
24
  // 8: TypeIndex
181
24
  // 12: Encoded Integer
182
24
  // <next>: Encoded Integer
183
24
  uint32_t Size = 12;
184
24
  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 2});
185
24
  Size += getEncodedIntegerLength(Data.drop_front(Size));
186
24
  Size += getEncodedIntegerLength(Data.drop_front(Size));
187
24
  return Size;
188
24
}
189
190
static uint32_t handleVFPtr(ArrayRef<uint8_t> Data, uint32_t Offset,
191
30
                            SmallVectorImpl<TiReference> &Refs) {
192
30
  // 0: Kind
193
30
  // 2: Padding
194
30
  // 4: TypeIndex
195
30
  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
196
30
  return 8;
197
30
}
198
199
static uint32_t handleListContinuation(ArrayRef<uint8_t> Data, uint32_t Offset,
200
10
                                       SmallVectorImpl<TiReference> &Refs) {
201
10
  // 0: Kind
202
10
  // 2: Padding
203
10
  // 4: TypeIndex
204
10
  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
205
10
  return 8;
206
10
}
207
208
static void handleFieldList(ArrayRef<uint8_t> Content,
209
1.04k
                            SmallVectorImpl<TiReference> &Refs) {
210
1.04k
  uint32_t Offset = 0;
211
1.04k
  uint32_t ThisLen = 0;
212
15.6k
  while (!Content.empty()) {
213
14.6k
    TypeLeafKind Kind =
214
14.6k
        static_cast<TypeLeafKind>(support::endian::read16le(Content.data()));
215
14.6k
    switch (Kind) {
216
14.6k
    case LF_BCLASS:
217
42
      ThisLen = handleBaseClass(Content, Offset, Refs);
218
42
      break;
219
14.6k
    case LF_ENUMERATE:
220
12.1k
      ThisLen = handleEnumerator(Content, Offset, Refs);
221
12.1k
      break;
222
14.6k
    case LF_MEMBER:
223
1.28k
      ThisLen = handleDataMember(Content, Offset, Refs);
224
1.28k
      break;
225
14.6k
    case LF_METHOD:
226
231
      ThisLen = handleOverloadedMethod(Content, Offset, Refs);
227
231
      break;
228
14.6k
    case LF_ONEMETHOD:
229
557
      ThisLen = handleOneMethod(Content, Offset, Refs);
230
557
      break;
231
14.6k
    case LF_NESTTYPE:
232
140
      ThisLen = handleNestedType(Content, Offset, Refs);
233
140
      break;
234
14.6k
    case LF_STMEMBER:
235
168
      ThisLen = handleStaticDataMember(Content, Offset, Refs);
236
168
      break;
237
14.6k
    case LF_VBCLASS:
238
24
    case LF_IVBCLASS:
239
24
      ThisLen =
240
24
          handleVirtualBaseClass(Content, Offset, Kind == LF_VBCLASS, Refs);
241
24
      break;
242
30
    case LF_VFUNCTAB:
243
30
      ThisLen = handleVFPtr(Content, Offset, Refs);
244
30
      break;
245
24
    case LF_INDEX:
246
10
      ThisLen = handleListContinuation(Content, Offset, Refs);
247
10
      break;
248
24
    default:
249
0
      return;
250
14.6k
    }
251
14.6k
    Content = Content.drop_front(ThisLen);
252
14.6k
    Offset += ThisLen;
253
14.6k
    if (!Content.empty()) {
254
14.2k
      uint8_t Pad = Content.front();
255
14.2k
      if (Pad >= LF_PAD0) {
256
4.29k
        uint32_t Skip = Pad & 0x0F;
257
4.29k
        Content = Content.drop_front(Skip);
258
4.29k
        Offset += Skip;
259
4.29k
      }
260
14.2k
    }
261
14.6k
  }
262
1.04k
}
263
264
static void handlePointer(ArrayRef<uint8_t> Content,
265
1.24k
                          SmallVectorImpl<TiReference> &Refs) {
266
1.24k
  Refs.push_back({TiRefKind::TypeRef, 0, 1});
267
1.24k
268
1.24k
  uint32_t Attrs = support::endian::read32le(Content.drop_front(4).data());
269
1.24k
  if (isMemberPointer(Attrs))
270
34
    Refs.push_back({TiRefKind::TypeRef, 8, 1});
271
1.24k
}
272
273
static void discoverTypeIndices(ArrayRef<uint8_t> Content, TypeLeafKind Kind,
274
10.2k
                                SmallVectorImpl<TiReference> &Refs) {
275
10.2k
  uint32_t Count;
276
10.2k
  // FIXME: In the future it would be nice if we could avoid hardcoding these
277
10.2k
  // values.  One idea is to define some structures representing these types
278
10.2k
  // that would allow the use of offsetof().
279
10.2k
  switch (Kind) {
280
10.2k
  case TypeLeafKind::LF_FUNC_ID:
281
528
    Refs.push_back({TiRefKind::IndexRef, 0, 1});
282
528
    Refs.push_back({TiRefKind::TypeRef, 4, 1});
283
528
    break;
284
10.2k
  case TypeLeafKind::LF_MFUNC_ID:
285
106
    Refs.push_back({TiRefKind::TypeRef, 0, 2});
286
106
    break;
287
10.2k
  case TypeLeafKind::LF_STRING_ID:
288
1.03k
    Refs.push_back({TiRefKind::IndexRef, 0, 1});
289
1.03k
    break;
290
10.2k
  case TypeLeafKind::LF_SUBSTR_LIST:
291
58
    Count = support::endian::read32le(Content.data());
292
58
    if (Count > 0)
293
58
      Refs.push_back({TiRefKind::IndexRef, 4, Count});
294
58
    break;
295
10.2k
  case TypeLeafKind::LF_BUILDINFO:
296
253
    Count = support::endian::read16le(Content.data());
297
253
    if (Count > 0)
298
253
      Refs.push_back({TiRefKind::IndexRef, 2, Count});
299
253
    break;
300
10.2k
  case TypeLeafKind::LF_UDT_SRC_LINE:
301
977
    Refs.push_back({TiRefKind::TypeRef, 0, 1});
302
977
    Refs.push_back({TiRefKind::IndexRef, 4, 1});
303
977
    break;
304
10.2k
  case TypeLeafKind::LF_UDT_MOD_SRC_LINE:
305
16
    Refs.push_back({TiRefKind::TypeRef, 0, 1});
306
16
    break;
307
10.2k
  case TypeLeafKind::LF_MODIFIER:
308
219
    Refs.push_back({TiRefKind::TypeRef, 0, 1});
309
219
    break;
310
10.2k
  case TypeLeafKind::LF_PROCEDURE:
311
428
    Refs.push_back({TiRefKind::TypeRef, 0, 1});
312
428
    Refs.push_back({TiRefKind::TypeRef, 8, 1});
313
428
    break;
314
10.2k
  case TypeLeafKind::LF_MFUNCTION:
315
1.18k
    Refs.push_back({TiRefKind::TypeRef, 0, 3});
316
1.18k
    Refs.push_back({TiRefKind::TypeRef, 16, 1});
317
1.18k
    break;
318
10.2k
  case TypeLeafKind::LF_ARGLIST:
319
862
    Count = support::endian::read32le(Content.data());
320
862
    if (Count > 0)
321
485
      Refs.push_back({TiRefKind::TypeRef, 4, Count});
322
862
    break;
323
10.2k
  case TypeLeafKind::LF_ARRAY:
324
55
    Refs.push_back({TiRefKind::TypeRef, 0, 2});
325
55
    break;
326
10.2k
  case TypeLeafKind::LF_CLASS:
327
1.77k
  case TypeLeafKind::LF_STRUCTURE:
328
1.77k
  case TypeLeafKind::LF_INTERFACE:
329
1.77k
    Refs.push_back({TiRefKind::TypeRef, 4, 3});
330
1.77k
    break;
331
1.77k
  case TypeLeafKind::LF_UNION:
332
52
    Refs.push_back({TiRefKind::TypeRef, 4, 1});
333
52
    break;
334
1.77k
  case TypeLeafKind::LF_ENUM:
335
134
    Refs.push_back({TiRefKind::TypeRef, 4, 2});
336
134
    break;
337
1.77k
  case TypeLeafKind::LF_BITFIELD:
338
14
    Refs.push_back({TiRefKind::TypeRef, 0, 1});
339
14
    break;
340
1.77k
  case TypeLeafKind::LF_VFTABLE:
341
8
    Refs.push_back({TiRefKind::TypeRef, 0, 2});
342
8
    break;
343
1.77k
  case TypeLeafKind::LF_VTSHAPE:
344
27
    break;
345
1.77k
  case TypeLeafKind::LF_METHODLIST:
346
231
    handleMethodOverloadList(Content, Refs);
347
231
    break;
348
1.77k
  case TypeLeafKind::LF_FIELDLIST:
349
1.04k
    handleFieldList(Content, Refs);
350
1.04k
    break;
351
1.77k
  case TypeLeafKind::LF_POINTER:
352
1.24k
    handlePointer(Content, Refs);
353
1.24k
    break;
354
1.77k
  default:
355
4
    break;
356
10.2k
  }
357
10.2k
}
358
359
static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind,
360
1.64k
                                SmallVectorImpl<TiReference> &Refs) {
361
1.64k
  uint32_t Count;
362
1.64k
  // FIXME: In the future it would be nice if we could avoid hardcoding these
363
1.64k
  // values.  One idea is to define some structures representing these types
364
1.64k
  // that would allow the use of offsetof().
365
1.64k
  switch (Kind) {
366
1.64k
  case SymbolKind::S_GPROC32_ID:
367
194
  case SymbolKind::S_LPROC32_ID:
368
194
  case SymbolKind::S_LPROC32_DPC:
369
194
  case SymbolKind::S_LPROC32_DPC_ID:
370
194
    Refs.push_back({TiRefKind::IndexRef, 24, 1}); // LF_FUNC_ID
371
194
    break;
372
194
  case SymbolKind::S_GPROC32:
373
22
  case SymbolKind::S_LPROC32:
374
22
    Refs.push_back({TiRefKind::TypeRef, 24, 1}); // Type
375
22
    break;
376
759
  case SymbolKind::S_UDT:
377
759
    Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UDT
378
759
    break;
379
36
  case SymbolKind::S_GDATA32:
380
36
  case SymbolKind::S_LDATA32:
381
36
    Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
382
36
    break;
383
55
  case SymbolKind::S_BUILDINFO:
384
55
    Refs.push_back({TiRefKind::IndexRef, 0, 1}); // Compile flags
385
55
    break;
386
36
  case SymbolKind::S_LTHREAD32:
387
0
  case SymbolKind::S_GTHREAD32:
388
0
    Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
389
0
    break;
390
3
  case SymbolKind::S_FILESTATIC:
391
3
    Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
392
3
    break;
393
50
  case SymbolKind::S_LOCAL:
394
50
    Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
395
50
    break;
396
1
  case SymbolKind::S_REGISTER:
397
1
    Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
398
1
    break;
399
4
  case SymbolKind::S_CONSTANT:
400
4
    Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
401
4
    break;
402
47
  case SymbolKind::S_BPREL32:
403
47
  case SymbolKind::S_REGREL32:
404
47
    Refs.push_back({TiRefKind::TypeRef, 4, 1}); // Type
405
47
    break;
406
47
  case SymbolKind::S_CALLSITEINFO:
407
0
    Refs.push_back({TiRefKind::TypeRef, 8, 1}); // Call signature
408
0
    break;
409
47
  case SymbolKind::S_CALLERS:
410
7
  case SymbolKind::S_CALLEES:
411
7
  case SymbolKind::S_INLINEES:
412
7
    // The record is a count followed by an array of type indices.
413
7
    Count = *reinterpret_cast<const ulittle32_t *>(Content.data());
414
7
    Refs.push_back({TiRefKind::IndexRef, 4, Count}); // Callees
415
7
    break;
416
7
  case SymbolKind::S_INLINESITE:
417
4
    Refs.push_back({TiRefKind::IndexRef, 8, 1}); // ID of inlinee
418
4
    break;
419
7
  case SymbolKind::S_HEAPALLOCSITE:
420
1
    Refs.push_back({TiRefKind::TypeRef, 8, 1}); // UDT allocated
421
1
    break;
422
7
423
7
  // Defranges don't have types, just registers and code offsets.
424
59
  case SymbolKind::S_DEFRANGE_REGISTER:
425
59
  case SymbolKind::S_DEFRANGE_REGISTER_REL:
426
59
  case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL:
427
59
  case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:
428
59
  case SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER:
429
59
  case SymbolKind::S_DEFRANGE_SUBFIELD:
430
59
    break;
431
59
432
59
  // No type references.
433
241
  case SymbolKind::S_LABEL32:
434
241
  case SymbolKind::S_OBJNAME:
435
241
  case SymbolKind::S_COMPILE:
436
241
  case SymbolKind::S_COMPILE2:
437
241
  case SymbolKind::S_COMPILE3:
438
241
  case SymbolKind::S_ENVBLOCK:
439
241
  case SymbolKind::S_BLOCK32:
440
241
  case SymbolKind::S_FRAMEPROC:
441
241
  case SymbolKind::S_THUNK32:
442
241
  case SymbolKind::S_FRAMECOOKIE:
443
241
  case SymbolKind::S_UNAMESPACE:
444
241
    break;
445
241
  // Scope ending symbols.
446
241
  case SymbolKind::S_END:
447
126
  case SymbolKind::S_INLINESITE_END:
448
126
  case SymbolKind::S_PROC_ID_END:
449
126
    break;
450
126
  default:
451
31
    return false; // Unknown symbol.
452
1.60k
  }
453
1.60k
  return true;
454
1.60k
}
455
456
void llvm::codeview::discoverTypeIndices(const CVType &Type,
457
93
                                         SmallVectorImpl<TiReference> &Refs) {
458
93
  ::discoverTypeIndices(Type.content(), Type.kind(), Refs);
459
93
}
460
461
static void resolveTypeIndexReferences(ArrayRef<uint8_t> RecordData,
462
                                       ArrayRef<TiReference> Refs,
463
289
                                       SmallVectorImpl<TypeIndex> &Indices) {
464
289
  Indices.clear();
465
289
466
289
  if (Refs.empty())
467
7
    return;
468
282
469
282
  RecordData = RecordData.drop_front(sizeof(RecordPrefix));
470
282
471
282
  BinaryStreamReader Reader(RecordData, support::little);
472
452
  for (const auto &Ref : Refs) {
473
452
    Reader.setOffset(Ref.Offset);
474
452
    FixedStreamArray<TypeIndex> Run;
475
452
    cantFail(Reader.readArray(Run, Ref.Count));
476
452
    Indices.append(Run.begin(), Run.end());
477
452
  }
478
282
}
479
480
void llvm::codeview::discoverTypeIndices(const CVType &Type,
481
289
                                         SmallVectorImpl<TypeIndex> &Indices) {
482
289
  return discoverTypeIndices(Type.RecordData, Indices);
483
289
}
484
485
void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
486
289
                                         SmallVectorImpl<TypeIndex> &Indices) {
487
289
  SmallVector<TiReference, 4> Refs;
488
289
  discoverTypeIndices(RecordData, Refs);
489
289
  resolveTypeIndexReferences(RecordData, Refs, Indices);
490
289
}
491
492
void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
493
10.1k
                                         SmallVectorImpl<TiReference> &Refs) {
494
10.1k
  const RecordPrefix *P =
495
10.1k
      reinterpret_cast<const RecordPrefix *>(RecordData.data());
496
10.1k
  TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind));
497
10.1k
  ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs);
498
10.1k
}
499
500
bool llvm::codeview::discoverTypeIndicesInSymbol(
501
1.64k
    const CVSymbol &Sym, SmallVectorImpl<TiReference> &Refs) {
502
1.64k
  SymbolKind K = Sym.kind();
503
1.64k
  return ::discoverTypeIndices(Sym.content(), K, Refs);
504
1.64k
}
505
506
bool llvm::codeview::discoverTypeIndicesInSymbol(
507
0
    ArrayRef<uint8_t> RecordData, SmallVectorImpl<TiReference> &Refs) {
508
0
  const RecordPrefix *P =
509
0
      reinterpret_cast<const RecordPrefix *>(RecordData.data());
510
0
  SymbolKind K = static_cast<SymbolKind>(uint16_t(P->RecordKind));
511
0
  return ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K,
512
0
                               Refs);
513
0
}
514
515
bool llvm::codeview::discoverTypeIndicesInSymbol(
516
0
    ArrayRef<uint8_t> RecordData, SmallVectorImpl<TypeIndex> &Indices) {
517
0
  SmallVector<TiReference, 2> Refs;
518
0
  if (!discoverTypeIndicesInSymbol(RecordData, Refs))
519
0
    return false;
520
0
  resolveTypeIndexReferences(RecordData, Refs, Indices);
521
0
  return true;
522
0
}