1 //===- TypeIndexDiscovery.cpp -----------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
8 #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/Support/Endian.h"
14 using namespace llvm::codeview
;
16 static inline MethodKind
getMethodKind(uint16_t Attrs
) {
17 Attrs
&= uint16_t(MethodOptions::MethodKindMask
);
19 return MethodKind(Attrs
);
22 static inline bool isIntroVirtual(uint16_t Attrs
) {
23 MethodKind MK
= getMethodKind(Attrs
);
24 return MK
== MethodKind::IntroducingVirtual
||
25 MK
== MethodKind::PureIntroducingVirtual
;
28 static inline PointerMode
getPointerMode(uint32_t Attrs
) {
29 return static_cast<PointerMode
>((Attrs
>> PointerRecord::PointerModeShift
) &
30 PointerRecord::PointerModeMask
);
33 static inline bool isMemberPointer(uint32_t Attrs
) {
34 PointerMode Mode
= getPointerMode(Attrs
);
35 return Mode
== PointerMode::PointerToDataMember
||
36 Mode
== PointerMode::PointerToMemberFunction
;
39 static inline uint32_t getEncodedIntegerLength(ArrayRef
<uint8_t> Data
) {
40 uint16_t N
= support::endian::read16le(Data
.data());
44 assert(N
<= LF_UQUADWORD
);
46 constexpr uint32_t Sizes
[] = {
60 return 2 + Sizes
[N
- LF_NUMERIC
];
63 static inline uint32_t getCStringLength(ArrayRef
<uint8_t> Data
) {
64 const char *S
= reinterpret_cast<const char *>(Data
.data());
68 static void handleMethodOverloadList(ArrayRef
<uint8_t> Content
,
69 SmallVectorImpl
<TiReference
> &Refs
) {
72 while (!Content
.empty()) {
77 // if (isIntroVirtual())
80 // At least 8 bytes are guaranteed. 4 extra bytes come iff function is an
84 uint16_t Attrs
= support::endian::read16le(Content
.data());
85 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
87 if (LLVM_UNLIKELY(isIntroVirtual(Attrs
)))
90 Content
= Content
.drop_front(Len
);
94 static uint32_t handleBaseClass(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
95 SmallVectorImpl
<TiReference
> &Refs
) {
100 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
101 return 8 + getEncodedIntegerLength(Data
.drop_front(8));
104 static uint32_t handleEnumerator(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
105 SmallVectorImpl
<TiReference
> &Refs
) {
108 // 4: Encoded Integer
110 uint32_t Size
= 4 + getEncodedIntegerLength(Data
.drop_front(4));
111 return Size
+ getCStringLength(Data
.drop_front(Size
));
114 static uint32_t handleDataMember(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
115 SmallVectorImpl
<TiReference
> &Refs
) {
119 // 8: Encoded Integer
121 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
122 uint32_t Size
= 8 + getEncodedIntegerLength(Data
.drop_front(8));
123 return Size
+ getCStringLength(Data
.drop_front(Size
));
126 static uint32_t handleOverloadedMethod(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
127 SmallVectorImpl
<TiReference
> &Refs
) {
132 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
133 return 8 + getCStringLength(Data
.drop_front(8));
136 static uint32_t handleOneMethod(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
137 SmallVectorImpl
<TiReference
> &Refs
) {
141 // if (isIntroVirtual)
145 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
147 uint16_t Attrs
= support::endian::read16le(Data
.drop_front(2).data());
148 if (LLVM_UNLIKELY(isIntroVirtual(Attrs
)))
151 return Size
+ getCStringLength(Data
.drop_front(Size
));
154 static uint32_t handleNestedType(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
155 SmallVectorImpl
<TiReference
> &Refs
) {
160 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
161 return 8 + getCStringLength(Data
.drop_front(8));
164 static uint32_t handleStaticDataMember(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
165 SmallVectorImpl
<TiReference
> &Refs
) {
170 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
171 return 8 + getCStringLength(Data
.drop_front(8));
174 static uint32_t handleVirtualBaseClass(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
176 SmallVectorImpl
<TiReference
> &Refs
) {
181 // 12: Encoded Integer
182 // <next>: Encoded Integer
184 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 2});
185 Size
+= getEncodedIntegerLength(Data
.drop_front(Size
));
186 Size
+= getEncodedIntegerLength(Data
.drop_front(Size
));
190 static uint32_t handleVFPtr(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
191 SmallVectorImpl
<TiReference
> &Refs
) {
195 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
199 static uint32_t handleListContinuation(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
200 SmallVectorImpl
<TiReference
> &Refs
) {
204 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
208 static void handleFieldList(ArrayRef
<uint8_t> Content
,
209 SmallVectorImpl
<TiReference
> &Refs
) {
211 uint32_t ThisLen
= 0;
212 while (!Content
.empty()) {
214 static_cast<TypeLeafKind
>(support::endian::read16le(Content
.data()));
217 ThisLen
= handleBaseClass(Content
, Offset
, Refs
);
220 ThisLen
= handleEnumerator(Content
, Offset
, Refs
);
223 ThisLen
= handleDataMember(Content
, Offset
, Refs
);
226 ThisLen
= handleOverloadedMethod(Content
, Offset
, Refs
);
229 ThisLen
= handleOneMethod(Content
, Offset
, Refs
);
232 ThisLen
= handleNestedType(Content
, Offset
, Refs
);
235 ThisLen
= handleStaticDataMember(Content
, Offset
, Refs
);
240 handleVirtualBaseClass(Content
, Offset
, Kind
== LF_VBCLASS
, Refs
);
243 ThisLen
= handleVFPtr(Content
, Offset
, Refs
);
246 ThisLen
= handleListContinuation(Content
, Offset
, Refs
);
251 Content
= Content
.drop_front(ThisLen
);
253 if (!Content
.empty()) {
254 uint8_t Pad
= Content
.front();
255 if (Pad
>= LF_PAD0
) {
256 uint32_t Skip
= Pad
& 0x0F;
257 Content
= Content
.drop_front(Skip
);
264 static void handlePointer(ArrayRef
<uint8_t> Content
,
265 SmallVectorImpl
<TiReference
> &Refs
) {
266 Refs
.push_back({TiRefKind::TypeRef
, 0, 1});
268 uint32_t Attrs
= support::endian::read32le(Content
.drop_front(4).data());
269 if (isMemberPointer(Attrs
))
270 Refs
.push_back({TiRefKind::TypeRef
, 8, 1});
273 static void discoverTypeIndices(ArrayRef
<uint8_t> Content
, TypeLeafKind Kind
,
274 SmallVectorImpl
<TiReference
> &Refs
) {
276 // FIXME: In the future it would be nice if we could avoid hardcoding these
277 // values. One idea is to define some structures representing these types
278 // that would allow the use of offsetof().
280 case TypeLeafKind::LF_FUNC_ID
:
281 Refs
.push_back({TiRefKind::IndexRef
, 0, 1});
282 Refs
.push_back({TiRefKind::TypeRef
, 4, 1});
284 case TypeLeafKind::LF_MFUNC_ID
:
285 Refs
.push_back({TiRefKind::TypeRef
, 0, 2});
287 case TypeLeafKind::LF_STRING_ID
:
288 Refs
.push_back({TiRefKind::IndexRef
, 0, 1});
290 case TypeLeafKind::LF_SUBSTR_LIST
:
291 Count
= support::endian::read32le(Content
.data());
293 Refs
.push_back({TiRefKind::IndexRef
, 4, Count
});
295 case TypeLeafKind::LF_BUILDINFO
:
296 Count
= support::endian::read16le(Content
.data());
298 Refs
.push_back({TiRefKind::IndexRef
, 2, Count
});
300 case TypeLeafKind::LF_UDT_SRC_LINE
:
301 Refs
.push_back({TiRefKind::TypeRef
, 0, 1});
302 Refs
.push_back({TiRefKind::IndexRef
, 4, 1});
304 case TypeLeafKind::LF_UDT_MOD_SRC_LINE
:
305 Refs
.push_back({TiRefKind::TypeRef
, 0, 1});
307 case TypeLeafKind::LF_MODIFIER
:
308 Refs
.push_back({TiRefKind::TypeRef
, 0, 1});
310 case TypeLeafKind::LF_PROCEDURE
:
311 Refs
.push_back({TiRefKind::TypeRef
, 0, 1});
312 Refs
.push_back({TiRefKind::TypeRef
, 8, 1});
314 case TypeLeafKind::LF_MFUNCTION
:
315 Refs
.push_back({TiRefKind::TypeRef
, 0, 3});
316 Refs
.push_back({TiRefKind::TypeRef
, 16, 1});
318 case TypeLeafKind::LF_ARGLIST
:
319 Count
= support::endian::read32le(Content
.data());
321 Refs
.push_back({TiRefKind::TypeRef
, 4, Count
});
323 case TypeLeafKind::LF_ARRAY
:
324 Refs
.push_back({TiRefKind::TypeRef
, 0, 2});
326 case TypeLeafKind::LF_CLASS
:
327 case TypeLeafKind::LF_STRUCTURE
:
328 case TypeLeafKind::LF_INTERFACE
:
329 Refs
.push_back({TiRefKind::TypeRef
, 4, 3});
331 case TypeLeafKind::LF_UNION
:
332 Refs
.push_back({TiRefKind::TypeRef
, 4, 1});
334 case TypeLeafKind::LF_ENUM
:
335 Refs
.push_back({TiRefKind::TypeRef
, 4, 2});
337 case TypeLeafKind::LF_BITFIELD
:
338 Refs
.push_back({TiRefKind::TypeRef
, 0, 1});
340 case TypeLeafKind::LF_VFTABLE
:
341 Refs
.push_back({TiRefKind::TypeRef
, 0, 2});
343 case TypeLeafKind::LF_VTSHAPE
:
345 case TypeLeafKind::LF_METHODLIST
:
346 handleMethodOverloadList(Content
, Refs
);
348 case TypeLeafKind::LF_FIELDLIST
:
349 handleFieldList(Content
, Refs
);
351 case TypeLeafKind::LF_POINTER
:
352 handlePointer(Content
, Refs
);
359 static bool discoverTypeIndices(ArrayRef
<uint8_t> Content
, SymbolKind Kind
,
360 SmallVectorImpl
<TiReference
> &Refs
) {
362 // FIXME: In the future it would be nice if we could avoid hardcoding these
363 // values. One idea is to define some structures representing these types
364 // that would allow the use of offsetof().
366 case SymbolKind::S_GPROC32_ID
:
367 case SymbolKind::S_LPROC32_ID
:
368 case SymbolKind::S_LPROC32_DPC
:
369 case SymbolKind::S_LPROC32_DPC_ID
:
370 Refs
.push_back({TiRefKind::IndexRef
, 24, 1}); // LF_FUNC_ID
372 case SymbolKind::S_GPROC32
:
373 case SymbolKind::S_LPROC32
:
374 Refs
.push_back({TiRefKind::TypeRef
, 24, 1}); // Type
376 case SymbolKind::S_UDT
:
377 Refs
.push_back({TiRefKind::TypeRef
, 0, 1}); // UDT
379 case SymbolKind::S_GDATA32
:
380 case SymbolKind::S_LDATA32
:
381 Refs
.push_back({TiRefKind::TypeRef
, 0, 1}); // Type
383 case SymbolKind::S_BUILDINFO
:
384 Refs
.push_back({TiRefKind::IndexRef
, 0, 1}); // Compile flags
386 case SymbolKind::S_LTHREAD32
:
387 case SymbolKind::S_GTHREAD32
:
388 Refs
.push_back({TiRefKind::TypeRef
, 0, 1}); // Type
390 case SymbolKind::S_FILESTATIC
:
391 Refs
.push_back({TiRefKind::TypeRef
, 0, 1}); // Type
393 case SymbolKind::S_LOCAL
:
394 Refs
.push_back({TiRefKind::TypeRef
, 0, 1}); // Type
396 case SymbolKind::S_REGISTER
:
397 Refs
.push_back({TiRefKind::TypeRef
, 0, 1}); // Type
399 case SymbolKind::S_CONSTANT
:
400 Refs
.push_back({TiRefKind::TypeRef
, 0, 1}); // Type
402 case SymbolKind::S_BPREL32
:
403 case SymbolKind::S_REGREL32
:
404 Refs
.push_back({TiRefKind::TypeRef
, 4, 1}); // Type
406 case SymbolKind::S_CALLSITEINFO
:
407 Refs
.push_back({TiRefKind::TypeRef
, 8, 1}); // Call signature
409 case SymbolKind::S_CALLERS
:
410 case SymbolKind::S_CALLEES
:
411 case SymbolKind::S_INLINEES
:
412 // The record is a count followed by an array of type indices.
413 Count
= *reinterpret_cast<const ulittle32_t
*>(Content
.data());
414 Refs
.push_back({TiRefKind::IndexRef
, 4, Count
}); // Callees
416 case SymbolKind::S_INLINESITE
:
417 Refs
.push_back({TiRefKind::IndexRef
, 8, 1}); // ID of inlinee
419 case SymbolKind::S_HEAPALLOCSITE
:
420 Refs
.push_back({TiRefKind::TypeRef
, 8, 1}); // UDT allocated
423 // Defranges don't have types, just registers and code offsets.
424 case SymbolKind::S_DEFRANGE_REGISTER
:
425 case SymbolKind::S_DEFRANGE_REGISTER_REL
:
426 case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL
:
427 case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE
:
428 case SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER
:
429 case SymbolKind::S_DEFRANGE_SUBFIELD
:
432 // No type references.
433 case SymbolKind::S_LABEL32
:
434 case SymbolKind::S_OBJNAME
:
435 case SymbolKind::S_COMPILE
:
436 case SymbolKind::S_COMPILE2
:
437 case SymbolKind::S_COMPILE3
:
438 case SymbolKind::S_ENVBLOCK
:
439 case SymbolKind::S_BLOCK32
:
440 case SymbolKind::S_FRAMEPROC
:
441 case SymbolKind::S_THUNK32
:
442 case SymbolKind::S_FRAMECOOKIE
:
443 case SymbolKind::S_UNAMESPACE
:
445 // Scope ending symbols.
446 case SymbolKind::S_END
:
447 case SymbolKind::S_INLINESITE_END
:
448 case SymbolKind::S_PROC_ID_END
:
451 return false; // Unknown symbol.
456 void llvm::codeview::discoverTypeIndices(const CVType
&Type
,
457 SmallVectorImpl
<TiReference
> &Refs
) {
458 ::discoverTypeIndices(Type
.content(), Type
.kind(), Refs
);
461 static void resolveTypeIndexReferences(ArrayRef
<uint8_t> RecordData
,
462 ArrayRef
<TiReference
> Refs
,
463 SmallVectorImpl
<TypeIndex
> &Indices
) {
469 RecordData
= RecordData
.drop_front(sizeof(RecordPrefix
));
471 BinaryStreamReader
Reader(RecordData
, support::little
);
472 for (const auto &Ref
: Refs
) {
473 Reader
.setOffset(Ref
.Offset
);
474 FixedStreamArray
<TypeIndex
> Run
;
475 cantFail(Reader
.readArray(Run
, Ref
.Count
));
476 Indices
.append(Run
.begin(), Run
.end());
480 void llvm::codeview::discoverTypeIndices(const CVType
&Type
,
481 SmallVectorImpl
<TypeIndex
> &Indices
) {
482 return discoverTypeIndices(Type
.RecordData
, Indices
);
485 void llvm::codeview::discoverTypeIndices(ArrayRef
<uint8_t> RecordData
,
486 SmallVectorImpl
<TypeIndex
> &Indices
) {
487 SmallVector
<TiReference
, 4> Refs
;
488 discoverTypeIndices(RecordData
, Refs
);
489 resolveTypeIndexReferences(RecordData
, Refs
, Indices
);
492 void llvm::codeview::discoverTypeIndices(ArrayRef
<uint8_t> RecordData
,
493 SmallVectorImpl
<TiReference
> &Refs
) {
494 const RecordPrefix
*P
=
495 reinterpret_cast<const RecordPrefix
*>(RecordData
.data());
496 TypeLeafKind K
= static_cast<TypeLeafKind
>(uint16_t(P
->RecordKind
));
497 ::discoverTypeIndices(RecordData
.drop_front(sizeof(RecordPrefix
)), K
, Refs
);
500 bool llvm::codeview::discoverTypeIndicesInSymbol(
501 const CVSymbol
&Sym
, SmallVectorImpl
<TiReference
> &Refs
) {
502 SymbolKind K
= Sym
.kind();
503 return ::discoverTypeIndices(Sym
.content(), K
, Refs
);
506 bool llvm::codeview::discoverTypeIndicesInSymbol(
507 ArrayRef
<uint8_t> RecordData
, SmallVectorImpl
<TiReference
> &Refs
) {
508 const RecordPrefix
*P
=
509 reinterpret_cast<const RecordPrefix
*>(RecordData
.data());
510 SymbolKind K
= static_cast<SymbolKind
>(uint16_t(P
->RecordKind
));
511 return ::discoverTypeIndices(RecordData
.drop_front(sizeof(RecordPrefix
)), K
,
515 bool llvm::codeview::discoverTypeIndicesInSymbol(
516 ArrayRef
<uint8_t> RecordData
, SmallVectorImpl
<TypeIndex
> &Indices
) {
517 SmallVector
<TiReference
, 2> Refs
;
518 if (!discoverTypeIndicesInSymbol(RecordData
, Refs
))
520 resolveTypeIndexReferences(RecordData
, Refs
, Indices
);