1 //===- TypeIndexDiscovery.cpp -----------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
11 #include "llvm/ADT/ArrayRef.h"
12 #include "llvm/Support/Endian.h"
15 using namespace llvm::codeview
;
17 static inline MethodKind
getMethodKind(uint16_t Attrs
) {
18 Attrs
&= uint16_t(MethodOptions::MethodKindMask
);
20 return MethodKind(Attrs
);
23 static inline bool isIntroVirtual(uint16_t Attrs
) {
24 MethodKind MK
= getMethodKind(Attrs
);
25 return MK
== MethodKind::IntroducingVirtual
||
26 MK
== MethodKind::PureIntroducingVirtual
;
29 static inline PointerMode
getPointerMode(uint32_t Attrs
) {
30 return static_cast<PointerMode
>((Attrs
>> PointerRecord::PointerModeShift
) &
31 PointerRecord::PointerModeMask
);
34 static inline bool isMemberPointer(uint32_t Attrs
) {
35 PointerMode Mode
= getPointerMode(Attrs
);
36 return Mode
== PointerMode::PointerToDataMember
||
37 Mode
== PointerMode::PointerToMemberFunction
;
40 static inline uint32_t getEncodedIntegerLength(ArrayRef
<uint8_t> Data
) {
41 uint16_t N
= support::endian::read16le(Data
.data());
45 assert(N
<= LF_UQUADWORD
);
47 constexpr uint32_t Sizes
[] = {
61 return 2 + Sizes
[N
- LF_NUMERIC
];
64 static inline uint32_t getCStringLength(ArrayRef
<uint8_t> Data
) {
65 const char *S
= reinterpret_cast<const char *>(Data
.data());
69 static void handleMethodOverloadList(ArrayRef
<uint8_t> Content
,
70 SmallVectorImpl
<TiReference
> &Refs
) {
73 while (!Content
.empty()) {
78 // if (isIntroVirtual())
81 // At least 8 bytes are guaranteed. 4 extra bytes come iff function is an
85 uint16_t Attrs
= support::endian::read16le(Content
.data());
86 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
88 if (LLVM_UNLIKELY(isIntroVirtual(Attrs
)))
91 Content
= Content
.drop_front(Len
);
95 static uint32_t handleBaseClass(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
96 SmallVectorImpl
<TiReference
> &Refs
) {
100 // 8: Encoded Integer
101 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
102 return 8 + getEncodedIntegerLength(Data
.drop_front(8));
105 static uint32_t handleEnumerator(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
106 SmallVectorImpl
<TiReference
> &Refs
) {
109 // 4: Encoded Integer
111 uint32_t Size
= 4 + getEncodedIntegerLength(Data
.drop_front(4));
112 return Size
+ getCStringLength(Data
.drop_front(Size
));
115 static uint32_t handleDataMember(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
116 SmallVectorImpl
<TiReference
> &Refs
) {
120 // 8: Encoded Integer
122 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
123 uint32_t Size
= 8 + getEncodedIntegerLength(Data
.drop_front(8));
124 return Size
+ getCStringLength(Data
.drop_front(Size
));
127 static uint32_t handleOverloadedMethod(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
128 SmallVectorImpl
<TiReference
> &Refs
) {
133 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
134 return 8 + getCStringLength(Data
.drop_front(8));
137 static uint32_t handleOneMethod(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
138 SmallVectorImpl
<TiReference
> &Refs
) {
142 // if (isIntroVirtual)
146 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
148 uint16_t Attrs
= support::endian::read16le(Data
.drop_front(2).data());
149 if (LLVM_UNLIKELY(isIntroVirtual(Attrs
)))
152 return Size
+ getCStringLength(Data
.drop_front(Size
));
155 static uint32_t handleNestedType(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
156 SmallVectorImpl
<TiReference
> &Refs
) {
161 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
162 return 8 + getCStringLength(Data
.drop_front(8));
165 static uint32_t handleStaticDataMember(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
166 SmallVectorImpl
<TiReference
> &Refs
) {
171 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
172 return 8 + getCStringLength(Data
.drop_front(8));
175 static uint32_t handleVirtualBaseClass(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
177 SmallVectorImpl
<TiReference
> &Refs
) {
182 // 12: Encoded Integer
183 // <next>: Encoded Integer
185 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 2});
186 Size
+= getEncodedIntegerLength(Data
.drop_front(Size
));
187 Size
+= getEncodedIntegerLength(Data
.drop_front(Size
));
191 static uint32_t handleVFPtr(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
192 SmallVectorImpl
<TiReference
> &Refs
) {
196 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
200 static uint32_t handleListContinuation(ArrayRef
<uint8_t> Data
, uint32_t Offset
,
201 SmallVectorImpl
<TiReference
> &Refs
) {
205 Refs
.push_back({TiRefKind::TypeRef
, Offset
+ 4, 1});
209 static void handleFieldList(ArrayRef
<uint8_t> Content
,
210 SmallVectorImpl
<TiReference
> &Refs
) {
212 uint32_t ThisLen
= 0;
213 while (!Content
.empty()) {
215 static_cast<TypeLeafKind
>(support::endian::read16le(Content
.data()));
218 ThisLen
= handleBaseClass(Content
, Offset
, Refs
);
221 ThisLen
= handleEnumerator(Content
, Offset
, Refs
);
224 ThisLen
= handleDataMember(Content
, Offset
, Refs
);
227 ThisLen
= handleOverloadedMethod(Content
, Offset
, Refs
);
230 ThisLen
= handleOneMethod(Content
, Offset
, Refs
);
233 ThisLen
= handleNestedType(Content
, Offset
, Refs
);
236 ThisLen
= handleStaticDataMember(Content
, Offset
, Refs
);
241 handleVirtualBaseClass(Content
, Offset
, Kind
== LF_VBCLASS
, Refs
);
244 ThisLen
= handleVFPtr(Content
, Offset
, Refs
);
247 ThisLen
= handleListContinuation(Content
, Offset
, Refs
);
252 Content
= Content
.drop_front(ThisLen
);
254 if (!Content
.empty()) {
255 uint8_t Pad
= Content
.front();
256 if (Pad
>= LF_PAD0
) {
257 uint32_t Skip
= Pad
& 0x0F;
258 Content
= Content
.drop_front(Skip
);
265 static void handlePointer(ArrayRef
<uint8_t> Content
,
266 SmallVectorImpl
<TiReference
> &Refs
) {
267 Refs
.push_back({TiRefKind::TypeRef
, 0, 1});
269 uint32_t Attrs
= support::endian::read32le(Content
.drop_front(4).data());
270 if (isMemberPointer(Attrs
))
271 Refs
.push_back({TiRefKind::TypeRef
, 8, 1});
274 static void discoverTypeIndices(ArrayRef
<uint8_t> Content
, TypeLeafKind Kind
,
275 SmallVectorImpl
<TiReference
> &Refs
) {
277 // FIXME: In the future it would be nice if we could avoid hardcoding these
278 // values. One idea is to define some structures representing these types
279 // that would allow the use of offsetof().
281 case TypeLeafKind::LF_FUNC_ID
:
282 Refs
.push_back({TiRefKind::IndexRef
, 0, 1});
283 Refs
.push_back({TiRefKind::TypeRef
, 4, 1});
285 case TypeLeafKind::LF_MFUNC_ID
:
286 Refs
.push_back({TiRefKind::TypeRef
, 0, 2});
288 case TypeLeafKind::LF_STRING_ID
:
289 Refs
.push_back({TiRefKind::IndexRef
, 0, 1});
291 case TypeLeafKind::LF_SUBSTR_LIST
:
292 Count
= support::endian::read32le(Content
.data());
294 Refs
.push_back({TiRefKind::IndexRef
, 4, Count
});
296 case TypeLeafKind::LF_BUILDINFO
:
297 Count
= support::endian::read16le(Content
.data());
299 Refs
.push_back({TiRefKind::IndexRef
, 2, Count
});
301 case TypeLeafKind::LF_UDT_SRC_LINE
:
302 Refs
.push_back({TiRefKind::TypeRef
, 0, 1});
303 Refs
.push_back({TiRefKind::IndexRef
, 4, 1});
305 case TypeLeafKind::LF_UDT_MOD_SRC_LINE
:
306 Refs
.push_back({TiRefKind::TypeRef
, 0, 1});
308 case TypeLeafKind::LF_MODIFIER
:
309 Refs
.push_back({TiRefKind::TypeRef
, 0, 1});
311 case TypeLeafKind::LF_PROCEDURE
:
312 Refs
.push_back({TiRefKind::TypeRef
, 0, 1});
313 Refs
.push_back({TiRefKind::TypeRef
, 8, 1});
315 case TypeLeafKind::LF_MFUNCTION
:
316 Refs
.push_back({TiRefKind::TypeRef
, 0, 3});
317 Refs
.push_back({TiRefKind::TypeRef
, 16, 1});
319 case TypeLeafKind::LF_ARGLIST
:
320 Count
= support::endian::read32le(Content
.data());
322 Refs
.push_back({TiRefKind::TypeRef
, 4, Count
});
324 case TypeLeafKind::LF_ARRAY
:
325 Refs
.push_back({TiRefKind::TypeRef
, 0, 2});
327 case TypeLeafKind::LF_CLASS
:
328 case TypeLeafKind::LF_STRUCTURE
:
329 case TypeLeafKind::LF_INTERFACE
:
330 Refs
.push_back({TiRefKind::TypeRef
, 4, 3});
332 case TypeLeafKind::LF_UNION
:
333 Refs
.push_back({TiRefKind::TypeRef
, 4, 1});
335 case TypeLeafKind::LF_ENUM
:
336 Refs
.push_back({TiRefKind::TypeRef
, 4, 2});
338 case TypeLeafKind::LF_BITFIELD
:
339 Refs
.push_back({TiRefKind::TypeRef
, 0, 1});
341 case TypeLeafKind::LF_VFTABLE
:
342 Refs
.push_back({TiRefKind::TypeRef
, 0, 2});
344 case TypeLeafKind::LF_VTSHAPE
:
346 case TypeLeafKind::LF_METHODLIST
:
347 handleMethodOverloadList(Content
, Refs
);
349 case TypeLeafKind::LF_FIELDLIST
:
350 handleFieldList(Content
, Refs
);
352 case TypeLeafKind::LF_POINTER
:
353 handlePointer(Content
, Refs
);
360 static bool discoverTypeIndices(ArrayRef
<uint8_t> Content
, SymbolKind Kind
,
361 SmallVectorImpl
<TiReference
> &Refs
) {
363 // FIXME: In the future it would be nice if we could avoid hardcoding these
364 // values. One idea is to define some structures representing these types
365 // that would allow the use of offsetof().
367 case SymbolKind::S_GPROC32
:
368 case SymbolKind::S_LPROC32
:
369 case SymbolKind::S_GPROC32_ID
:
370 case SymbolKind::S_LPROC32_ID
:
371 case SymbolKind::S_LPROC32_DPC
:
372 case SymbolKind::S_LPROC32_DPC_ID
:
373 Refs
.push_back({TiRefKind::IndexRef
, 24, 1}); // LF_FUNC_ID
375 case SymbolKind::S_UDT
:
376 Refs
.push_back({TiRefKind::TypeRef
, 0, 1}); // UDT
378 case SymbolKind::S_GDATA32
:
379 case SymbolKind::S_LDATA32
:
380 Refs
.push_back({TiRefKind::TypeRef
, 0, 1}); // Type
382 case SymbolKind::S_BUILDINFO
:
383 Refs
.push_back({TiRefKind::IndexRef
, 0, 1}); // Compile flags
385 case SymbolKind::S_LTHREAD32
:
386 case SymbolKind::S_GTHREAD32
:
387 Refs
.push_back({TiRefKind::TypeRef
, 0, 1}); // Type
389 case SymbolKind::S_FILESTATIC
:
390 Refs
.push_back({TiRefKind::TypeRef
, 0, 1}); // Type
392 case SymbolKind::S_LOCAL
:
393 Refs
.push_back({TiRefKind::TypeRef
, 0, 1}); // Type
395 case SymbolKind::S_REGISTER
:
396 Refs
.push_back({TiRefKind::TypeRef
, 0, 1}); // Type
398 case SymbolKind::S_CONSTANT
:
399 Refs
.push_back({TiRefKind::TypeRef
, 0, 1}); // Type
401 case SymbolKind::S_BPREL32
:
402 case SymbolKind::S_REGREL32
:
403 Refs
.push_back({TiRefKind::TypeRef
, 4, 1}); // Type
405 case SymbolKind::S_CALLSITEINFO
:
406 Refs
.push_back({TiRefKind::TypeRef
, 8, 1}); // Call signature
408 case SymbolKind::S_CALLERS
:
409 case SymbolKind::S_CALLEES
:
410 case SymbolKind::S_INLINEES
:
411 // The record is a count followed by an array of type indices.
412 Count
= *reinterpret_cast<const ulittle32_t
*>(Content
.data());
413 Refs
.push_back({TiRefKind::IndexRef
, 4, Count
}); // Callees
415 case SymbolKind::S_INLINESITE
:
416 Refs
.push_back({TiRefKind::IndexRef
, 8, 1}); // ID of inlinee
418 case SymbolKind::S_HEAPALLOCSITE
:
419 Refs
.push_back({TiRefKind::TypeRef
, 8, 1}); // UDT allocated
422 // Defranges don't have types, just registers and code offsets.
423 case SymbolKind::S_DEFRANGE_REGISTER
:
424 case SymbolKind::S_DEFRANGE_REGISTER_REL
:
425 case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL
:
426 case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE
:
427 case SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER
:
428 case SymbolKind::S_DEFRANGE_SUBFIELD
:
431 // No type references.
432 case SymbolKind::S_LABEL32
:
433 case SymbolKind::S_OBJNAME
:
434 case SymbolKind::S_COMPILE
:
435 case SymbolKind::S_COMPILE2
:
436 case SymbolKind::S_COMPILE3
:
437 case SymbolKind::S_ENVBLOCK
:
438 case SymbolKind::S_BLOCK32
:
439 case SymbolKind::S_FRAMEPROC
:
440 case SymbolKind::S_THUNK32
:
441 case SymbolKind::S_FRAMECOOKIE
:
442 case SymbolKind::S_UNAMESPACE
:
444 // Scope ending symbols.
445 case SymbolKind::S_END
:
446 case SymbolKind::S_INLINESITE_END
:
447 case SymbolKind::S_PROC_ID_END
:
450 return false; // Unknown symbol.
455 void llvm::codeview::discoverTypeIndices(const CVType
&Type
,
456 SmallVectorImpl
<TiReference
> &Refs
) {
457 ::discoverTypeIndices(Type
.content(), Type
.kind(), Refs
);
460 static void resolveTypeIndexReferences(ArrayRef
<uint8_t> RecordData
,
461 ArrayRef
<TiReference
> Refs
,
462 SmallVectorImpl
<TypeIndex
> &Indices
) {
468 RecordData
= RecordData
.drop_front(sizeof(RecordPrefix
));
470 BinaryStreamReader
Reader(RecordData
, support::little
);
471 for (const auto &Ref
: Refs
) {
472 Reader
.setOffset(Ref
.Offset
);
473 FixedStreamArray
<TypeIndex
> Run
;
474 cantFail(Reader
.readArray(Run
, Ref
.Count
));
475 Indices
.append(Run
.begin(), Run
.end());
479 void llvm::codeview::discoverTypeIndices(const CVType
&Type
,
480 SmallVectorImpl
<TypeIndex
> &Indices
) {
481 return discoverTypeIndices(Type
.RecordData
, Indices
);
484 void llvm::codeview::discoverTypeIndices(ArrayRef
<uint8_t> RecordData
,
485 SmallVectorImpl
<TypeIndex
> &Indices
) {
486 SmallVector
<TiReference
, 4> Refs
;
487 discoverTypeIndices(RecordData
, Refs
);
488 resolveTypeIndexReferences(RecordData
, Refs
, Indices
);
491 void llvm::codeview::discoverTypeIndices(ArrayRef
<uint8_t> RecordData
,
492 SmallVectorImpl
<TiReference
> &Refs
) {
493 const RecordPrefix
*P
=
494 reinterpret_cast<const RecordPrefix
*>(RecordData
.data());
495 TypeLeafKind K
= static_cast<TypeLeafKind
>(uint16_t(P
->RecordKind
));
496 ::discoverTypeIndices(RecordData
.drop_front(sizeof(RecordPrefix
)), K
, Refs
);
499 bool llvm::codeview::discoverTypeIndicesInSymbol(
500 const CVSymbol
&Sym
, SmallVectorImpl
<TiReference
> &Refs
) {
501 SymbolKind K
= Sym
.kind();
502 return ::discoverTypeIndices(Sym
.content(), K
, Refs
);
505 bool llvm::codeview::discoverTypeIndicesInSymbol(
506 ArrayRef
<uint8_t> RecordData
, SmallVectorImpl
<TiReference
> &Refs
) {
507 const RecordPrefix
*P
=
508 reinterpret_cast<const RecordPrefix
*>(RecordData
.data());
509 SymbolKind K
= static_cast<SymbolKind
>(uint16_t(P
->RecordKind
));
510 return ::discoverTypeIndices(RecordData
.drop_front(sizeof(RecordPrefix
)), K
,
514 bool llvm::codeview::discoverTypeIndicesInSymbol(
515 ArrayRef
<uint8_t> RecordData
, SmallVectorImpl
<TypeIndex
> &Indices
) {
516 SmallVector
<TiReference
, 2> Refs
;
517 if (!discoverTypeIndicesInSymbol(RecordData
, Refs
))
519 resolveTypeIndexReferences(RecordData
, Refs
, Indices
);