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);