LLVM  8.0.1
TypeIndexDiscovery.cpp
Go to the documentation of this file.
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 //===----------------------------------------------------------------------===//
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  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 ||
27 }
28 
30  return static_cast<PointerMode>((Attrs >> PointerRecord::PointerModeShift) &
32 }
33 
34 static inline bool isMemberPointer(uint32_t Attrs) {
36  return Mode == PointerMode::PointerToDataMember ||
38 }
39 
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 
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 
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 
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
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});
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 
209 static void handleFieldList(ArrayRef<uint8_t> Content,
211  uint32_t Offset = 0;
212  uint32_t ThisLen = 0;
213  while (!Content.empty()) {
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,
267  Refs.push_back({TiRefKind::TypeRef, 0, 1});
268 
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:
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 
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:
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  Refs.push_back({TiRefKind::IndexRef, 24, 1}); // LF_FUNC_ID
374  break;
375  case SymbolKind::S_UDT:
376  Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UDT
377  break;
378  case SymbolKind::S_GDATA32:
379  case SymbolKind::S_LDATA32:
380  Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
381  break;
382  case SymbolKind::S_BUILDINFO:
383  Refs.push_back({TiRefKind::IndexRef, 0, 1}); // Compile flags
384  break;
385  case SymbolKind::S_LTHREAD32:
386  case SymbolKind::S_GTHREAD32:
387  Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
388  break;
389  case SymbolKind::S_FILESTATIC:
390  Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
391  break;
392  case SymbolKind::S_LOCAL:
393  Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
394  break;
395  case SymbolKind::S_REGISTER:
396  Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
397  break;
398  case SymbolKind::S_CONSTANT:
399  Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
400  break;
401  case SymbolKind::S_BPREL32:
402  case SymbolKind::S_REGREL32:
403  Refs.push_back({TiRefKind::TypeRef, 4, 1}); // Type
404  break;
405  case SymbolKind::S_CALLSITEINFO:
406  Refs.push_back({TiRefKind::TypeRef, 8, 1}); // Call signature
407  break;
408  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  Count = *reinterpret_cast<const ulittle32_t *>(Content.data());
413  Refs.push_back({TiRefKind::IndexRef, 4, Count}); // Callees
414  break;
415  case SymbolKind::S_INLINESITE:
416  Refs.push_back({TiRefKind::IndexRef, 8, 1}); // ID of inlinee
417  break;
418  case SymbolKind::S_HEAPALLOCSITE:
419  Refs.push_back({TiRefKind::TypeRef, 8, 1}); // UDT allocated
420  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 
457  ::discoverTypeIndices(Type.content(), Type.kind(), Refs);
458 }
459 
462  SmallVectorImpl<TypeIndex> &Indices) {
463  Indices.clear();
464 
465  if (Refs.empty())
466  return;
467 
468  RecordData = RecordData.drop_front(sizeof(RecordPrefix));
469 
470  BinaryStreamReader Reader(RecordData, support::little);
471  for (const auto &Ref : Refs) {
472  Reader.setOffset(Ref.Offset);
474  cantFail(Reader.readArray(Run, Ref.Count));
475  Indices.append(Run.begin(), Run.end());
476  }
477 }
478 
480  SmallVectorImpl<TypeIndex> &Indices) {
481  return discoverTypeIndices(Type.RecordData, Indices);
482 }
483 
485  SmallVectorImpl<TypeIndex> &Indices) {
487  discoverTypeIndices(RecordData, Refs);
488  resolveTypeIndexReferences(RecordData, Refs, Indices);
489 }
490 
493  const RecordPrefix *P =
494  reinterpret_cast<const RecordPrefix *>(RecordData.data());
495  TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind));
496  ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs);
497 }
498 
500  const CVSymbol &Sym, SmallVectorImpl<TiReference> &Refs) {
501  SymbolKind K = Sym.kind();
502  return ::discoverTypeIndices(Sym.content(), K, Refs);
503 }
504 
507  const RecordPrefix *P =
508  reinterpret_cast<const RecordPrefix *>(RecordData.data());
509  SymbolKind K = static_cast<SymbolKind>(uint16_t(P->RecordKind));
511  Refs);
512 }
513 
515  ArrayRef<uint8_t> RecordData, SmallVectorImpl<TypeIndex> &Indices) {
517  if (!discoverTypeIndicesInSymbol(RecordData, Refs))
518  return false;
519  resolveTypeIndexReferences(RecordData, Refs, Indices);
520  return true;
521 }
const T & front() const
front - Get the first element.
Definition: ArrayRef.h:152
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition: Error.h:704
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:37
SI Whole Quad Mode
This class represents lattice values for constants.
Definition: AllocatorList.h:24
TypeLeafKind
Duplicate copy of the above enum, but using the official CV names.
Definition: CodeView.h:34
uint16_t read16le(const void *P)
Definition: Endian.h:368
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)
#define LLVM_UNLIKELY(EXPR)
Definition: Compiler.h:192
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:42
The access may reference the value stored in memory.
ArrayRef< uint8_t > content() const
Definition: CVRecord.h:44
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:46
detail::packed_endian_specific_integral< uint32_t, little, unaligned > ulittle32_t
Definition: Endian.h:271
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:146
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:847
static uint32_t handleDataMember(ArrayRef< uint8_t > Data, uint32_t Offset, SmallVectorImpl< TiReference > &Refs)
PointerMode
Equivalent to CV_ptrmode_e.
Definition: CodeView.h:345
static const uint32_t PointerModeMask
Definition: TypeRecord.h:278
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:394
static const uint32_t PointerModeShift
Definition: TypeRecord.h:277
ArrayRef< uint8_t > RecordData
Definition: CVRecord.h:49
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
Definition: ArrayRef.h:188
#define N
static bool isMemberPointer(uint32_t Attrs)
uint32_t read32le(const void *P)
Definition: Endian.h:369
uint32_t Size
Definition: Profile.cpp:47
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:48
const unsigned Kind
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:144