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 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 refernces.
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:
443 // Scope ending symbols.
444 case SymbolKind::S_END:
445 case SymbolKind::S_INLINESITE_END:
446 case SymbolKind::S_PROC_ID_END:
449 return false; // Unknown symbol.
454 void llvm::codeview::discoverTypeIndices(const CVType &Type,
455 SmallVectorImpl<TiReference> &Refs) {
456 ::discoverTypeIndices(Type.content(), Type.kind(), Refs);
459 static void resolveTypeIndexReferences(ArrayRef<uint8_t> RecordData,
460 ArrayRef<TiReference> Refs,
461 SmallVectorImpl<TypeIndex> &Indices) {
467 RecordData = RecordData.drop_front(sizeof(RecordPrefix));
469 BinaryStreamReader Reader(RecordData, support::little);
470 for (const auto &Ref : Refs) {
471 Reader.setOffset(Ref.Offset);
472 FixedStreamArray<TypeIndex> Run;
473 cantFail(Reader.readArray(Run, Ref.Count));
474 Indices.append(Run.begin(), Run.end());
478 void llvm::codeview::discoverTypeIndices(const CVType &Type,
479 SmallVectorImpl<TypeIndex> &Indices) {
480 return discoverTypeIndices(Type.RecordData, Indices);
483 void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
484 SmallVectorImpl<TypeIndex> &Indices) {
485 SmallVector<TiReference, 4> Refs;
486 discoverTypeIndices(RecordData, Refs);
487 resolveTypeIndexReferences(RecordData, Refs, Indices);
490 void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
491 SmallVectorImpl<TiReference> &Refs) {
492 const RecordPrefix *P =
493 reinterpret_cast<const RecordPrefix *>(RecordData.data());
494 TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind));
495 ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs);
498 bool llvm::codeview::discoverTypeIndicesInSymbol(
499 const CVSymbol &Sym, SmallVectorImpl<TiReference> &Refs) {
500 SymbolKind K = Sym.kind();
501 return ::discoverTypeIndices(Sym.content(), K, Refs);
504 bool llvm::codeview::discoverTypeIndicesInSymbol(
505 ArrayRef<uint8_t> RecordData, SmallVectorImpl<TiReference> &Refs) {
506 const RecordPrefix *P =
507 reinterpret_cast<const RecordPrefix *>(RecordData.data());
508 SymbolKind K = static_cast<SymbolKind>(uint16_t(P->RecordKind));
509 return ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K,
513 bool llvm::codeview::discoverTypeIndicesInSymbol(
514 ArrayRef<uint8_t> RecordData, SmallVectorImpl<TypeIndex> &Indices) {
515 SmallVector<TiReference, 2> Refs;
516 if (!discoverTypeIndicesInSymbol(RecordData, Refs))
518 resolveTypeIndexReferences(RecordData, Refs, Indices);