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