Line data Source code
1 : //===- TypeIndexDiscovery.cpp -----------------------------------*- C++ -*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
10 :
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 161 : Attrs &= uint16_t(MethodOptions::MethodKindMask);
19 161 : Attrs >>= 2;
20 161 : return MethodKind(Attrs);
21 : }
22 :
23 : static inline bool isIntroVirtual(uint16_t Attrs) {
24 : MethodKind MK = getMethodKind(Attrs);
25 161 : return MK == MethodKind::IntroducingVirtual ||
26 161 : MK == MethodKind::PureIntroducingVirtual;
27 : }
28 :
29 : static inline PointerMode getPointerMode(uint32_t Attrs) {
30 0 : return static_cast<PointerMode>((Attrs >> PointerRecord::PointerModeShift) &
31 0 : PointerRecord::PointerModeMask);
32 : }
33 :
34 : static inline bool isMemberPointer(uint32_t Attrs) {
35 : PointerMode Mode = getPointerMode(Attrs);
36 0 : return Mode == PointerMode::PointerToDataMember ||
37 : Mode == PointerMode::PointerToMemberFunction;
38 : }
39 :
40 0 : static inline uint32_t getEncodedIntegerLength(ArrayRef<uint8_t> Data) {
41 0 : uint16_t N = support::endian::read16le(Data.data());
42 18 : if (N < LF_NUMERIC)
43 0 : return 2;
44 :
45 : assert(N <= LF_UQUADWORD);
46 :
47 0 : 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 0 : return 2 + Sizes[N - LF_NUMERIC];
62 : }
63 :
64 0 : static inline uint32_t getCStringLength(ArrayRef<uint8_t> Data) {
65 0 : const char *S = reinterpret_cast<const char *>(Data.data());
66 0 : return strlen(S) + 1;
67 : }
68 :
69 67 : static void handleMethodOverloadList(ArrayRef<uint8_t> Content,
70 : SmallVectorImpl<TiReference> &Refs) {
71 : uint32_t Offset = 0;
72 :
73 228 : 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 161 : Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
87 :
88 161 : if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
89 : Len += 4;
90 161 : Offset += Len;
91 161 : Content = Content.drop_front(Len);
92 : }
93 67 : }
94 :
95 0 : 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 0 : Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
102 0 : return 8 + getEncodedIntegerLength(Data.drop_front(8));
103 : }
104 :
105 0 : 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 0 : uint32_t Size = 4 + getEncodedIntegerLength(Data.drop_front(4));
112 0 : return Size + getCStringLength(Data.drop_front(Size));
113 : }
114 :
115 0 : 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 0 : Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
123 0 : uint32_t Size = 8 + getEncodedIntegerLength(Data.drop_front(8));
124 0 : return Size + getCStringLength(Data.drop_front(Size));
125 : }
126 :
127 0 : 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 0 : Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
134 0 : return 8 + getCStringLength(Data.drop_front(8));
135 : }
136 :
137 0 : 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 0 : Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
147 :
148 0 : uint16_t Attrs = support::endian::read16le(Data.drop_front(2).data());
149 0 : if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
150 : Size += 4;
151 :
152 0 : return Size + getCStringLength(Data.drop_front(Size));
153 : }
154 :
155 0 : 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 0 : Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
162 0 : return 8 + getCStringLength(Data.drop_front(8));
163 : }
164 :
165 0 : 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 0 : Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
172 0 : return 8 + getCStringLength(Data.drop_front(8));
173 : }
174 :
175 18 : 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 18 : Refs.push_back({TiRefKind::TypeRef, Offset + 4, 2});
186 18 : Size += getEncodedIntegerLength(Data.drop_front(Size));
187 18 : Size += getEncodedIntegerLength(Data.drop_front(Size));
188 18 : return Size;
189 : }
190 :
191 0 : 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 20 : Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
197 0 : return 8;
198 : }
199 :
200 0 : 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 6 : Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
206 0 : return 8;
207 : }
208 :
209 289 : static void handleFieldList(ArrayRef<uint8_t> Content,
210 : SmallVectorImpl<TiReference> &Refs) {
211 : uint32_t Offset = 0;
212 : uint32_t ThisLen = 0;
213 7132 : while (!Content.empty()) {
214 : TypeLeafKind Kind =
215 : static_cast<TypeLeafKind>(support::endian::read16le(Content.data()));
216 6843 : switch (Kind) {
217 26 : case LF_BCLASS:
218 26 : ThisLen = handleBaseClass(Content, Offset, Refs);
219 26 : break;
220 6163 : case LF_ENUMERATE:
221 6163 : ThisLen = handleEnumerator(Content, Offset, Refs);
222 6163 : break;
223 339 : case LF_MEMBER:
224 339 : ThisLen = handleDataMember(Content, Offset, Refs);
225 339 : break;
226 67 : case LF_METHOD:
227 67 : ThisLen = handleOverloadedMethod(Content, Offset, Refs);
228 67 : break;
229 114 : case LF_ONEMETHOD:
230 114 : ThisLen = handleOneMethod(Content, Offset, Refs);
231 114 : break;
232 81 : case LF_NESTTYPE:
233 81 : ThisLen = handleNestedType(Content, Offset, Refs);
234 81 : break;
235 9 : case LF_STMEMBER:
236 9 : ThisLen = handleStaticDataMember(Content, Offset, Refs);
237 9 : break;
238 18 : case LF_VBCLASS:
239 : case LF_IVBCLASS:
240 : ThisLen =
241 18 : handleVirtualBaseClass(Content, Offset, Kind == LF_VBCLASS, Refs);
242 18 : break;
243 : case LF_VFUNCTAB:
244 : ThisLen = handleVFPtr(Content, Offset, Refs);
245 20 : break;
246 : case LF_INDEX:
247 : ThisLen = handleListContinuation(Content, Offset, Refs);
248 6 : break;
249 : default:
250 : return;
251 : }
252 6843 : Content = Content.drop_front(ThisLen);
253 6843 : Offset += ThisLen;
254 6843 : if (!Content.empty()) {
255 6743 : uint8_t Pad = Content.front();
256 6743 : if (Pad >= LF_PAD0) {
257 1802 : uint32_t Skip = Pad & 0x0F;
258 1802 : Content = Content.drop_front(Skip);
259 1802 : Offset += Skip;
260 : }
261 : }
262 : }
263 : }
264 :
265 0 : static void handlePointer(ArrayRef<uint8_t> Content,
266 : SmallVectorImpl<TiReference> &Refs) {
267 0 : Refs.push_back({TiRefKind::TypeRef, 0, 1});
268 :
269 0 : uint32_t Attrs = support::endian::read32le(Content.drop_front(4).data());
270 0 : if (isMemberPointer(Attrs))
271 0 : Refs.push_back({TiRefKind::TypeRef, 8, 1});
272 0 : }
273 :
274 3994 : 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 3994 : switch (Kind) {
281 365 : case TypeLeafKind::LF_FUNC_ID:
282 365 : Refs.push_back({TiRefKind::IndexRef, 0, 1});
283 365 : Refs.push_back({TiRefKind::TypeRef, 4, 1});
284 365 : break;
285 75 : case TypeLeafKind::LF_MFUNC_ID:
286 75 : Refs.push_back({TiRefKind::TypeRef, 0, 2});
287 75 : break;
288 652 : case TypeLeafKind::LF_STRING_ID:
289 652 : Refs.push_back({TiRefKind::IndexRef, 0, 1});
290 652 : break;
291 42 : case TypeLeafKind::LF_SUBSTR_LIST:
292 : Count = support::endian::read32le(Content.data());
293 42 : if (Count > 0)
294 42 : Refs.push_back({TiRefKind::IndexRef, 4, Count});
295 : break;
296 173 : case TypeLeafKind::LF_BUILDINFO:
297 173 : Count = support::endian::read16le(Content.data());
298 173 : if (Count > 0)
299 173 : Refs.push_back({TiRefKind::IndexRef, 2, Count});
300 : break;
301 246 : case TypeLeafKind::LF_UDT_SRC_LINE:
302 246 : Refs.push_back({TiRefKind::TypeRef, 0, 1});
303 246 : Refs.push_back({TiRefKind::IndexRef, 4, 1});
304 246 : break;
305 9 : case TypeLeafKind::LF_UDT_MOD_SRC_LINE:
306 9 : Refs.push_back({TiRefKind::TypeRef, 0, 1});
307 9 : break;
308 106 : case TypeLeafKind::LF_MODIFIER:
309 106 : Refs.push_back({TiRefKind::TypeRef, 0, 1});
310 106 : break;
311 267 : case TypeLeafKind::LF_PROCEDURE:
312 267 : Refs.push_back({TiRefKind::TypeRef, 0, 1});
313 267 : Refs.push_back({TiRefKind::TypeRef, 8, 1});
314 267 : break;
315 293 : case TypeLeafKind::LF_MFUNCTION:
316 293 : Refs.push_back({TiRefKind::TypeRef, 0, 3});
317 293 : Refs.push_back({TiRefKind::TypeRef, 16, 1});
318 293 : break;
319 467 : case TypeLeafKind::LF_ARGLIST:
320 : Count = support::endian::read32le(Content.data());
321 467 : if (Count > 0)
322 244 : Refs.push_back({TiRefKind::TypeRef, 4, Count});
323 : break;
324 28 : case TypeLeafKind::LF_ARRAY:
325 28 : Refs.push_back({TiRefKind::TypeRef, 0, 2});
326 28 : break;
327 384 : case TypeLeafKind::LF_CLASS:
328 : case TypeLeafKind::LF_STRUCTURE:
329 : case TypeLeafKind::LF_INTERFACE:
330 384 : Refs.push_back({TiRefKind::TypeRef, 4, 3});
331 384 : break;
332 21 : case TypeLeafKind::LF_UNION:
333 21 : Refs.push_back({TiRefKind::TypeRef, 4, 1});
334 21 : break;
335 77 : case TypeLeafKind::LF_ENUM:
336 77 : Refs.push_back({TiRefKind::TypeRef, 4, 2});
337 77 : break;
338 14 : case TypeLeafKind::LF_BITFIELD:
339 14 : Refs.push_back({TiRefKind::TypeRef, 0, 1});
340 14 : break;
341 8 : case TypeLeafKind::LF_VFTABLE:
342 8 : Refs.push_back({TiRefKind::TypeRef, 0, 2});
343 8 : break;
344 : case TypeLeafKind::LF_VTSHAPE:
345 : break;
346 67 : case TypeLeafKind::LF_METHODLIST:
347 67 : handleMethodOverloadList(Content, Refs);
348 67 : break;
349 289 : case TypeLeafKind::LF_FIELDLIST:
350 289 : handleFieldList(Content, Refs);
351 289 : break;
352 388 : case TypeLeafKind::LF_POINTER:
353 388 : handlePointer(Content, Refs);
354 388 : break;
355 : default:
356 : break;
357 : }
358 3994 : }
359 :
360 645 : 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 645 : switch (Kind) {
367 150 : 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 150 : Refs.push_back({TiRefKind::IndexRef, 24, 1}); // LF_FUNC_ID
374 150 : break;
375 94 : case SymbolKind::S_UDT:
376 94 : Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UDT
377 94 : break;
378 20 : case SymbolKind::S_GDATA32:
379 : case SymbolKind::S_LDATA32:
380 20 : Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
381 20 : break;
382 36 : case SymbolKind::S_BUILDINFO:
383 36 : Refs.push_back({TiRefKind::IndexRef, 0, 1}); // Compile flags
384 36 : break;
385 0 : case SymbolKind::S_LTHREAD32:
386 : case SymbolKind::S_GTHREAD32:
387 0 : Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
388 0 : break;
389 3 : case SymbolKind::S_FILESTATIC:
390 3 : Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
391 3 : break;
392 37 : case SymbolKind::S_LOCAL:
393 37 : Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
394 37 : break;
395 1 : case SymbolKind::S_REGISTER:
396 1 : Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
397 1 : break;
398 0 : case SymbolKind::S_CONSTANT:
399 0 : Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
400 0 : break;
401 22 : case SymbolKind::S_BPREL32:
402 : case SymbolKind::S_REGREL32:
403 22 : Refs.push_back({TiRefKind::TypeRef, 4, 1}); // Type
404 22 : break;
405 0 : case SymbolKind::S_CALLSITEINFO:
406 0 : Refs.push_back({TiRefKind::TypeRef, 8, 1}); // Call signature
407 0 : break;
408 7 : 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 7 : Count = *reinterpret_cast<const ulittle32_t *>(Content.data());
413 7 : Refs.push_back({TiRefKind::IndexRef, 4, Count}); // Callees
414 7 : break;
415 1 : case SymbolKind::S_INLINESITE:
416 1 : Refs.push_back({TiRefKind::IndexRef, 8, 1}); // ID of inlinee
417 1 : break;
418 1 : case SymbolKind::S_HEAPALLOCSITE:
419 1 : Refs.push_back({TiRefKind::TypeRef, 8, 1}); // UDT allocated
420 1 : break;
421 :
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:
429 : break;
430 :
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:
443 : break;
444 : // Scope ending symbols.
445 : case SymbolKind::S_END:
446 : case SymbolKind::S_INLINESITE_END:
447 : case SymbolKind::S_PROC_ID_END:
448 : break;
449 : default:
450 : return false; // Unknown symbol.
451 : }
452 : return true;
453 : }
454 :
455 0 : void llvm::codeview::discoverTypeIndices(const CVType &Type,
456 : SmallVectorImpl<TiReference> &Refs) {
457 0 : ::discoverTypeIndices(Type.content(), Type.kind(), Refs);
458 0 : }
459 :
460 263 : static void resolveTypeIndexReferences(ArrayRef<uint8_t> RecordData,
461 : ArrayRef<TiReference> Refs,
462 : SmallVectorImpl<TypeIndex> &Indices) {
463 : Indices.clear();
464 :
465 263 : if (Refs.empty())
466 6 : return;
467 :
468 : RecordData = RecordData.drop_front(sizeof(RecordPrefix));
469 :
470 257 : BinaryStreamReader Reader(RecordData, support::little);
471 663 : for (const auto &Ref : Refs) {
472 406 : Reader.setOffset(Ref.Offset);
473 : FixedStreamArray<TypeIndex> Run;
474 406 : cantFail(Reader.readArray(Run, Ref.Count));
475 1624 : Indices.append(Run.begin(), Run.end());
476 : }
477 : }
478 :
479 263 : void llvm::codeview::discoverTypeIndices(const CVType &Type,
480 : SmallVectorImpl<TypeIndex> &Indices) {
481 263 : return discoverTypeIndices(Type.RecordData, Indices);
482 : }
483 :
484 263 : void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
485 : SmallVectorImpl<TypeIndex> &Indices) {
486 : SmallVector<TiReference, 4> Refs;
487 263 : discoverTypeIndices(RecordData, Refs);
488 263 : resolveTypeIndexReferences(RecordData, Refs, Indices);
489 263 : }
490 :
491 3994 : 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 7988 : ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs);
497 3994 : }
498 :
499 645 : bool llvm::codeview::discoverTypeIndicesInSymbol(
500 : const CVSymbol &Sym, SmallVectorImpl<TiReference> &Refs) {
501 645 : SymbolKind K = Sym.kind();
502 1290 : return ::discoverTypeIndices(Sym.content(), K, Refs);
503 : }
504 :
505 0 : 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 0 : return ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K,
511 0 : Refs);
512 : }
513 :
514 0 : bool llvm::codeview::discoverTypeIndicesInSymbol(
515 : ArrayRef<uint8_t> RecordData, SmallVectorImpl<TypeIndex> &Indices) {
516 : SmallVector<TiReference, 2> Refs;
517 0 : if (!discoverTypeIndicesInSymbol(RecordData, Refs))
518 : return false;
519 0 : resolveTypeIndexReferences(RecordData, Refs, Indices);
520 0 : return true;
521 : }
|