LLVM 20.0.0git
TypeIndexDiscovery.cpp
Go to the documentation of this file.
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
11#include "llvm/ADT/ArrayRef.h"
12#include "llvm/Support/Endian.h"
13
14using namespace llvm;
15using namespace llvm::codeview;
16
17static inline MethodKind getMethodKind(uint16_t Attrs) {
18 Attrs &= uint16_t(MethodOptions::MethodKindMask);
19 Attrs >>= 2;
20 return MethodKind(Attrs);
21}
22
23static inline bool isIntroVirtual(uint16_t Attrs) {
24 MethodKind MK = getMethodKind(Attrs);
25 return MK == MethodKind::IntroducingVirtual ||
26 MK == MethodKind::PureIntroducingVirtual;
27}
28
29static inline PointerMode getPointerMode(uint32_t Attrs) {
30 return static_cast<PointerMode>((Attrs >> PointerRecord::PointerModeShift) &
32}
33
34static inline bool isMemberPointer(uint32_t Attrs) {
35 PointerMode Mode = getPointerMode(Attrs);
36 return Mode == PointerMode::PointerToDataMember ||
37 Mode == PointerMode::PointerToMemberFunction;
38}
39
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
65 const char *S = reinterpret_cast<const char *>(Data.data());
66 return strlen(S) + 1;
67}
68
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
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
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
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
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
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
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
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
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
176 bool IsIndirect,
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
193 // 0: Kind
194 // 2: Padding
195 // 4: TypeIndex
196 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
197 return 8;
198}
199
202 // 0: Kind
203 // 2: Padding
204 // 4: TypeIndex
205 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
206 return 8;
207}
208
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
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
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:
348 break;
349 case TypeLeafKind::LF_FIELDLIST:
351 break;
352 case TypeLeafKind::LF_POINTER:
353 handlePointer(Content, Refs);
354 break;
355 default:
356 break;
357 }
358}
359
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 case SymbolKind::S_ARMSWITCHTABLE:
446 break;
447 // Scope ending symbols.
448 case SymbolKind::S_END:
449 case SymbolKind::S_INLINESITE_END:
450 case SymbolKind::S_PROC_ID_END:
451 break;
452 default:
453 return false; // Unknown symbol.
454 }
455 return true;
456}
457
460 ::discoverTypeIndices(Type.content(), Type.kind(), Refs);
461}
462
466 Indices.clear();
467
468 if (Refs.empty())
469 return;
470
471 RecordData = RecordData.drop_front(sizeof(RecordPrefix));
472
474 for (const auto &Ref : Refs) {
475 Reader.setOffset(Ref.Offset);
477 cantFail(Reader.readArray(Run, Ref.Count));
478 Indices.append(Run.begin(), Run.end());
479 }
480}
481
484 return discoverTypeIndices(Type.RecordData, Indices);
485}
486
490 discoverTypeIndices(RecordData, Refs);
491 resolveTypeIndexReferences(RecordData, Refs, Indices);
492}
493
496 const RecordPrefix *P =
497 reinterpret_cast<const RecordPrefix *>(RecordData.data());
498 TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind));
499 ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs);
500}
501
504 SymbolKind K = Sym.kind();
505 return ::discoverTypeIndices(Sym.content(), K, Refs);
506}
507
510 const RecordPrefix *P =
511 reinterpret_cast<const RecordPrefix *>(RecordData.data());
512 SymbolKind K = static_cast<SymbolKind>(uint16_t(P->RecordKind));
513 return ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K,
514 Refs);
515}
516
518 ArrayRef<uint8_t> RecordData, SmallVectorImpl<TypeIndex> &Indices) {
520 if (!discoverTypeIndicesInSymbol(RecordData, Refs))
521 return false;
522 resolveTypeIndexReferences(RecordData, Refs, Indices);
523 return true;
524}
#define LLVM_UNLIKELY(EXPR)
Definition: Compiler.h:237
T Content
uint64_t Size
Symbol * Sym
Definition: ELF_riscv.cpp:479
#define P(N)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static uint32_t getCStringLength(ArrayRef< uint8_t > Data)
static uint32_t handleDataMember(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
static uint32_t handleListContinuation(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
static void discoverTypeIndices(ArrayRef< uint8_t > Content, TypeLeafKind Kind, SmallVectorImpl< TiReference > &Refs)
static void resolveTypeIndexReferences(ArrayRef< uint8_t > RecordData, ArrayRef< TiReference > Refs, SmallVectorImpl< TypeIndex > &Indices)
static uint32_t handleEnumerator(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
static bool isMemberPointer(uint32_t Attrs)
static uint32_t handleNestedType(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
static uint32_t getEncodedIntegerLength(ArrayRef< uint8_t > Data)
static uint32_t handleVFPtr(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
static uint32_t handleOneMethod(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
static void handleFieldList(ArrayRef< uint8_t > Content, SmallVectorImpl< TiReference > &Refs)
static uint32_t handleBaseClass(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
static void handlePointer(ArrayRef< uint8_t > Content, SmallVectorImpl< TiReference > &Refs)
static void handleMethodOverloadList(ArrayRef< uint8_t > Content, SmallVectorImpl< TiReference > &Refs)
static uint32_t handleVirtualBaseClass(ArrayRef< uint8_t > Data, uint32_t Offset, bool IsIndirect, SmallVectorImpl< TiReference > &Refs)
static PointerMode getPointerMode(uint32_t Attrs)
static MethodKind getMethodKind(uint16_t Attrs)
static uint32_t handleOverloadedMethod(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
static bool isIntroVirtual(uint16_t Attrs)
static uint32_t handleStaticDataMember(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
Definition: ArrayRef.h:204
bool empty() const
empty - Check if the array is empty.
Definition: ArrayRef.h:160
const T * data() const
Definition: ArrayRef.h:162
Provides read only access to a subclass of BinaryStream.
void setOffset(uint64_t Off)
Error readArray(ArrayRef< T > &Array, uint32_t NumElements)
Get a reference to a NumElements element array of objects of type T from the underlying stream as if ...
FixedStreamArray is similar to VarStreamArray, except with each record having a fixed-length.
FixedStreamArrayIterator< T > begin() const
FixedStreamArrayIterator< T > end() const
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:586
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
Definition: SmallVector.h:696
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
static const uint32_t PointerModeShift
Definition: TypeRecord.h:271
static const uint32_t PointerModeMask
Definition: TypeRecord.h:272
PointerMode
Equivalent to CV_ptrmode_e.
Definition: CodeView.h:363
bool discoverTypeIndicesInSymbol(const CVSymbol &Symbol, SmallVectorImpl< TiReference > &Refs)
Discover type indices in symbol records.
MethodKind
Part of member attribute flags. (CV_methodprop_e)
Definition: CodeView.h:280
void discoverTypeIndices(ArrayRef< uint8_t > RecordData, SmallVectorImpl< TiReference > &Refs)
TypeLeafKind
Duplicate copy of the above enum, but using the official CV names.
Definition: CodeView.h:34
SymbolKind
Duplicate copy of the above enum, but using the official CV names.
Definition: CodeView.h:48
uint16_t read16le(const void *P)
Definition: Endian.h:422
uint32_t read32le(const void *P)
Definition: Endian.h:425
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:480
@ Ref
The access may reference the value stored in memory.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition: Error.h:756
#define N