LLVM  10.0.0svn
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 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/Support/Endian.h"
12 
13 using namespace llvm;
14 using namespace llvm::codeview;
15 
16 static inline MethodKind getMethodKind(uint16_t Attrs) {
17  Attrs &= uint16_t(MethodOptions::MethodKindMask);
18  Attrs >>= 2;
19  return MethodKind(Attrs);
20 }
21 
22 static inline bool isIntroVirtual(uint16_t Attrs) {
23  MethodKind MK = getMethodKind(Attrs);
24  return MK == MethodKind::IntroducingVirtual ||
26 }
27 
29  return static_cast<PointerMode>((Attrs >> PointerRecord::PointerModeShift) &
31 }
32 
33 static inline bool isMemberPointer(uint32_t Attrs) {
35  return Mode == PointerMode::PointerToDataMember ||
37 }
38 
40  uint16_t N = support::endian::read16le(Data.data());
41  if (N < LF_NUMERIC)
42  return 2;
43 
44  assert(N <= LF_UQUADWORD);
45 
46  constexpr uint32_t Sizes[] = {
47  1, // LF_CHAR
48  2, // LF_SHORT
49  2, // LF_USHORT
50  4, // LF_LONG
51  4, // LF_ULONG
52  4, // LF_REAL32
53  8, // LF_REAL64
54  10, // LF_REAL80
55  16, // LF_REAL128
56  8, // LF_QUADWORD
57  8, // LF_UQUADWORD
58  };
59 
60  return 2 + Sizes[N - LF_NUMERIC];
61 }
62 
64  const char *S = reinterpret_cast<const char *>(Data.data());
65  return strlen(S) + 1;
66 }
67 
70  uint32_t Offset = 0;
71 
72  while (!Content.empty()) {
73  // Array of:
74  // 0: Attrs
75  // 2: Padding
76  // 4: TypeIndex
77  // if (isIntroVirtual())
78  // 8: VFTableOffset
79 
80  // At least 8 bytes are guaranteed. 4 extra bytes come iff function is an
81  // intro virtual.
82  uint32_t Len = 8;
83 
84  uint16_t Attrs = support::endian::read16le(Content.data());
85  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
86 
87  if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
88  Len += 4;
89  Offset += Len;
90  Content = Content.drop_front(Len);
91  }
92 }
93 
96  // 0: Kind
97  // 2: Padding
98  // 4: TypeIndex
99  // 8: Encoded Integer
100  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
101  return 8 + getEncodedIntegerLength(Data.drop_front(8));
102 }
103 
106  // 0: Kind
107  // 2: Padding
108  // 4: Encoded Integer
109  // <next>: Name
111  return Size + getCStringLength(Data.drop_front(Size));
112 }
113 
116  // 0: Kind
117  // 2: Padding
118  // 4: TypeIndex
119  // 8: Encoded Integer
120  // <next>: Name
121  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
123  return Size + getCStringLength(Data.drop_front(Size));
124 }
125 
128  // 0: Kind
129  // 2: Padding
130  // 4: TypeIndex
131  // 8: Name
132  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
133  return 8 + getCStringLength(Data.drop_front(8));
134 }
135 
138  // 0: Kind
139  // 2: Attributes
140  // 4: Type
141  // if (isIntroVirtual)
142  // 8: VFTableOffset
143  // <next>: Name
144  uint32_t Size = 8;
145  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
146 
147  uint16_t Attrs = support::endian::read16le(Data.drop_front(2).data());
148  if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
149  Size += 4;
150 
151  return Size + getCStringLength(Data.drop_front(Size));
152 }
153 
156  // 0: Kind
157  // 2: Padding
158  // 4: TypeIndex
159  // 8: Name
160  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
161  return 8 + getCStringLength(Data.drop_front(8));
162 }
163 
166  // 0: Kind
167  // 2: Padding
168  // 4: TypeIndex
169  // 8: Name
170  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
171  return 8 + getCStringLength(Data.drop_front(8));
172 }
173 
175  bool IsIndirect,
177  // 0: Kind
178  // 2: Attrs
179  // 4: TypeIndex
180  // 8: TypeIndex
181  // 12: Encoded Integer
182  // <next>: Encoded Integer
183  uint32_t Size = 12;
184  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 2});
185  Size += getEncodedIntegerLength(Data.drop_front(Size));
186  Size += getEncodedIntegerLength(Data.drop_front(Size));
187  return Size;
188 }
189 
192  // 0: Kind
193  // 2: Padding
194  // 4: TypeIndex
195  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
196  return 8;
197 }
198 
201  // 0: Kind
202  // 2: Padding
203  // 4: TypeIndex
204  Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
205  return 8;
206 }
207 
208 static void handleFieldList(ArrayRef<uint8_t> Content,
210  uint32_t Offset = 0;
211  uint32_t ThisLen = 0;
212  while (!Content.empty()) {
214  static_cast<TypeLeafKind>(support::endian::read16le(Content.data()));
215  switch (Kind) {
216  case LF_BCLASS:
217  ThisLen = handleBaseClass(Content, Offset, Refs);
218  break;
219  case LF_ENUMERATE:
220  ThisLen = handleEnumerator(Content, Offset, Refs);
221  break;
222  case LF_MEMBER:
223  ThisLen = handleDataMember(Content, Offset, Refs);
224  break;
225  case LF_METHOD:
226  ThisLen = handleOverloadedMethod(Content, Offset, Refs);
227  break;
228  case LF_ONEMETHOD:
229  ThisLen = handleOneMethod(Content, Offset, Refs);
230  break;
231  case LF_NESTTYPE:
232  ThisLen = handleNestedType(Content, Offset, Refs);
233  break;
234  case LF_STMEMBER:
235  ThisLen = handleStaticDataMember(Content, Offset, Refs);
236  break;
237  case LF_VBCLASS:
238  case LF_IVBCLASS:
239  ThisLen =
240  handleVirtualBaseClass(Content, Offset, Kind == LF_VBCLASS, Refs);
241  break;
242  case LF_VFUNCTAB:
243  ThisLen = handleVFPtr(Content, Offset, Refs);
244  break;
245  case LF_INDEX:
246  ThisLen = handleListContinuation(Content, Offset, Refs);
247  break;
248  default:
249  return;
250  }
251  Content = Content.drop_front(ThisLen);
252  Offset += 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);
258  Offset += Skip;
259  }
260  }
261  }
262 }
263 
264 static void handlePointer(ArrayRef<uint8_t> Content,
266  Refs.push_back({TiRefKind::TypeRef, 0, 1});
267 
269  if (isMemberPointer(Attrs))
270  Refs.push_back({TiRefKind::TypeRef, 8, 1});
271 }
272 
275  uint32_t Count;
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().
279  switch (Kind) {
280  case TypeLeafKind::LF_FUNC_ID:
281  Refs.push_back({TiRefKind::IndexRef, 0, 1});
282  Refs.push_back({TiRefKind::TypeRef, 4, 1});
283  break;
284  case TypeLeafKind::LF_MFUNC_ID:
285  Refs.push_back({TiRefKind::TypeRef, 0, 2});
286  break;
287  case TypeLeafKind::LF_STRING_ID:
288  Refs.push_back({TiRefKind::IndexRef, 0, 1});
289  break;
290  case TypeLeafKind::LF_SUBSTR_LIST:
291  Count = support::endian::read32le(Content.data());
292  if (Count > 0)
293  Refs.push_back({TiRefKind::IndexRef, 4, Count});
294  break;
295  case TypeLeafKind::LF_BUILDINFO:
296  Count = support::endian::read16le(Content.data());
297  if (Count > 0)
298  Refs.push_back({TiRefKind::IndexRef, 2, Count});
299  break;
300  case TypeLeafKind::LF_UDT_SRC_LINE:
301  Refs.push_back({TiRefKind::TypeRef, 0, 1});
302  Refs.push_back({TiRefKind::IndexRef, 4, 1});
303  break;
304  case TypeLeafKind::LF_UDT_MOD_SRC_LINE:
305  Refs.push_back({TiRefKind::TypeRef, 0, 1});
306  break;
307  case TypeLeafKind::LF_MODIFIER:
308  Refs.push_back({TiRefKind::TypeRef, 0, 1});
309  break;
310  case TypeLeafKind::LF_PROCEDURE:
311  Refs.push_back({TiRefKind::TypeRef, 0, 1});
312  Refs.push_back({TiRefKind::TypeRef, 8, 1});
313  break;
314  case TypeLeafKind::LF_MFUNCTION:
315  Refs.push_back({TiRefKind::TypeRef, 0, 3});
316  Refs.push_back({TiRefKind::TypeRef, 16, 1});
317  break;
318  case TypeLeafKind::LF_ARGLIST:
319  Count = support::endian::read32le(Content.data());
320  if (Count > 0)
321  Refs.push_back({TiRefKind::TypeRef, 4, Count});
322  break;
323  case TypeLeafKind::LF_ARRAY:
324  Refs.push_back({TiRefKind::TypeRef, 0, 2});
325  break;
326  case TypeLeafKind::LF_CLASS:
327  case TypeLeafKind::LF_STRUCTURE:
328  case TypeLeafKind::LF_INTERFACE:
329  Refs.push_back({TiRefKind::TypeRef, 4, 3});
330  break;
331  case TypeLeafKind::LF_UNION:
332  Refs.push_back({TiRefKind::TypeRef, 4, 1});
333  break;
334  case TypeLeafKind::LF_ENUM:
335  Refs.push_back({TiRefKind::TypeRef, 4, 2});
336  break;
337  case TypeLeafKind::LF_BITFIELD:
338  Refs.push_back({TiRefKind::TypeRef, 0, 1});
339  break;
340  case TypeLeafKind::LF_VFTABLE:
341  Refs.push_back({TiRefKind::TypeRef, 0, 2});
342  break;
343  case TypeLeafKind::LF_VTSHAPE:
344  break;
345  case TypeLeafKind::LF_METHODLIST:
346  handleMethodOverloadList(Content, Refs);
347  break;
348  case TypeLeafKind::LF_FIELDLIST:
349  handleFieldList(Content, Refs);
350  break;
351  case TypeLeafKind::LF_POINTER:
352  handlePointer(Content, Refs);
353  break;
354  default:
355  break;
356  }
357 }
358 
361  uint32_t Count;
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().
365  switch (Kind) {
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
371  break;
372  case SymbolKind::S_GPROC32:
373  case SymbolKind::S_LPROC32:
374  Refs.push_back({TiRefKind::TypeRef, 24, 1}); // Type
375  break;
376  case SymbolKind::S_UDT:
377  Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UDT
378  break;
379  case SymbolKind::S_GDATA32:
380  case SymbolKind::S_LDATA32:
381  Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
382  break;
383  case SymbolKind::S_BUILDINFO:
384  Refs.push_back({TiRefKind::IndexRef, 0, 1}); // Compile flags
385  break;
386  case SymbolKind::S_LTHREAD32:
387  case SymbolKind::S_GTHREAD32:
388  Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
389  break;
390  case SymbolKind::S_FILESTATIC:
391  Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
392  break;
393  case SymbolKind::S_LOCAL:
394  Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
395  break;
396  case SymbolKind::S_REGISTER:
397  Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
398  break;
399  case SymbolKind::S_CONSTANT:
400  Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
401  break;
402  case SymbolKind::S_BPREL32:
403  case SymbolKind::S_REGREL32:
404  Refs.push_back({TiRefKind::TypeRef, 4, 1}); // Type
405  break;
406  case SymbolKind::S_CALLSITEINFO:
407  Refs.push_back({TiRefKind::TypeRef, 8, 1}); // Call signature
408  break;
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
415  break;
416  case SymbolKind::S_INLINESITE:
417  Refs.push_back({TiRefKind::IndexRef, 8, 1}); // ID of inlinee
418  break;
419  case SymbolKind::S_HEAPALLOCSITE:
420  Refs.push_back({TiRefKind::TypeRef, 8, 1}); // UDT allocated
421  break;
422 
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:
430  break;
431 
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:
444  break;
445  // Scope ending symbols.
446  case SymbolKind::S_END:
447  case SymbolKind::S_INLINESITE_END:
448  case SymbolKind::S_PROC_ID_END:
449  break;
450  default:
451  return false; // Unknown symbol.
452  }
453  return true;
454 }
455 
458  ::discoverTypeIndices(Type.content(), Type.kind(), Refs);
459 }
460 
463  SmallVectorImpl<TypeIndex> &Indices) {
464  Indices.clear();
465 
466  if (Refs.empty())
467  return;
468 
469  RecordData = RecordData.drop_front(sizeof(RecordPrefix));
470 
471  BinaryStreamReader Reader(RecordData, support::little);
472  for (const auto &Ref : Refs) {
473  Reader.setOffset(Ref.Offset);
475  cantFail(Reader.readArray(Run, Ref.Count));
476  Indices.append(Run.begin(), Run.end());
477  }
478 }
479 
481  SmallVectorImpl<TypeIndex> &Indices) {
482  return discoverTypeIndices(Type.RecordData, Indices);
483 }
484 
486  SmallVectorImpl<TypeIndex> &Indices) {
488  discoverTypeIndices(RecordData, Refs);
489  resolveTypeIndexReferences(RecordData, Refs, Indices);
490 }
491 
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);
498 }
499 
501  const CVSymbol &Sym, SmallVectorImpl<TiReference> &Refs) {
502  SymbolKind K = Sym.kind();
503  return ::discoverTypeIndices(Sym.content(), K, Refs);
504 }
505 
508  const RecordPrefix *P =
509  reinterpret_cast<const RecordPrefix *>(RecordData.data());
510  SymbolKind K = static_cast<SymbolKind>(uint16_t(P->RecordKind));
512  Refs);
513 }
514 
516  ArrayRef<uint8_t> RecordData, SmallVectorImpl<TypeIndex> &Indices) {
518  if (!discoverTypeIndicesInSymbol(RecordData, Refs))
519  return false;
520  resolveTypeIndexReferences(RecordData, Refs, Indices);
521  return true;
522 }
const T & front() const
front - Get the first element.
Definition: ArrayRef.h:151
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition: Error.h:703
static uint32_t handleBaseClass(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
void discoverTypeIndices(ArrayRef< uint8_t > RecordData, SmallVectorImpl< TiReference > &Refs)
Kind kind() const
Definition: CVRecord.h:43
SI Whole Quad Mode
This class represents lattice values for constants.
Definition: AllocatorList.h:23
TypeLeafKind
Duplicate copy of the above enum, but using the official CV names.
Definition: CodeView.h:33
#define LLVM_UNLIKELY(EXPR)
Definition: Compiler.h:199
uint16_t read16le(const void *P)
Definition: Endian.h:382
FixedStreamArray is similar to VarStreamArray, except with each record having a fixed-length.
static uint32_t handleOneMethod(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
static uint32_t handleVirtualBaseClass(ArrayRef< uint8_t > Data, uint32_t Offset, bool IsIndirect, SmallVectorImpl< TiReference > &Refs)
static void handleFieldList(ArrayRef< uint8_t > Content, SmallVectorImpl< TiReference > &Refs)
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: APFloat.h:41
The access may reference the value stored in memory.
ArrayRef< uint8_t > content() const
Definition: CVRecord.h:57
static MethodKind getMethodKind(uint16_t Attrs)
static bool isIntroVirtual(uint16_t Attrs)
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
MethodKind
Part of member attribute flags. (CV_methodprop_e)
Definition: CodeView.h:268
static uint32_t getCStringLength(ArrayRef< uint8_t > Data)
#define P(N)
static uint32_t handleListContinuation(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
static uint32_t getEncodedIntegerLength(ArrayRef< uint8_t > Data)
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:45
detail::packed_endian_specific_integral< uint32_t, little, unaligned > ulittle32_t
Definition: Endian.h:274
bool discoverTypeIndicesInSymbol(const CVSymbol &Symbol, SmallVectorImpl< TiReference > &Refs)
Discover type indices in symbol records.
static uint32_t handleOverloadedMethod(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
static uint32_t handleStaticDataMember(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
const T * data() const
Definition: ArrayRef.h:145
static uint32_t handleEnumerator(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
static void handleMethodOverloadList(ArrayRef< uint8_t > Content, SmallVectorImpl< TiReference > &Refs)
static PointerMode getPointerMode(uint32_t Attrs)
void setOffset(uint32_t Off)
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:837
static uint32_t handleDataMember(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
PointerMode
Equivalent to CV_ptrmode_e.
Definition: CodeView.h:348
static const uint32_t PointerModeMask
Definition: TypeRecord.h:277
static void discoverTypeIndices(ArrayRef< uint8_t > Content, TypeLeafKind Kind, SmallVectorImpl< TiReference > &Refs)
void append(in_iter in_start, in_iter in_end)
Add the specified range to the end of the SmallVector.
Definition: SmallVector.h:387
static const uint32_t PointerModeShift
Definition: TypeRecord.h:276
ArrayRef< uint8_t > RecordData
Definition: CVRecord.h:61
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
Definition: ArrayRef.h:187
#define N
static bool isMemberPointer(uint32_t Attrs)
uint32_t read32le(const void *P)
Definition: Endian.h:383
uint32_t Size
Definition: Profile.cpp:46
static void resolveTypeIndexReferences(ArrayRef< uint8_t > RecordData, ArrayRef< TiReference > Refs, SmallVectorImpl< TypeIndex > &Indices)
static void handlePointer(ArrayRef< uint8_t > Content, SmallVectorImpl< TiReference > &Refs)
SymbolKind
Duplicate copy of the above enum, but using the official CV names.
Definition: CodeView.h:47
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
FixedStreamArrayIterator< T > end() const
static uint32_t handleVFPtr(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
Provides read only access to a subclass of BinaryStream.
static uint32_t handleNestedType(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
FixedStreamArrayIterator< T > begin() const
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 ...
bool empty() const
empty - Check if the array is empty.
Definition: ArrayRef.h:143