LLVM  10.0.0svn
TypeRecordMapping.cpp
Go to the documentation of this file.
1 //===- TypeRecordMapping.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 
10 
11 using namespace llvm;
12 using namespace llvm::codeview;
13 
14 #define error(X) \
15  if (auto EC = X) \
16  return EC;
17 
18 namespace {
19 struct MapOneMethodRecord {
20  explicit MapOneMethodRecord(bool IsFromOverloadList)
21  : IsFromOverloadList(IsFromOverloadList) {}
22 
23  Error operator()(CodeViewRecordIO &IO, OneMethodRecord &Method) const {
24  error(IO.mapInteger(Method.Attrs.Attrs, "AccessSpecifier"));
25  if (IsFromOverloadList) {
26  uint16_t Padding = 0;
27  error(IO.mapInteger(Padding, "Padding"));
28  }
29  error(IO.mapInteger(Method.Type, "Type"));
30  if (Method.isIntroducingVirtual()) {
31  error(IO.mapInteger(Method.VFTableOffset, "VFTableOffset"));
32  } else if (IO.isReading())
33  Method.VFTableOffset = -1;
34 
35  if (!IsFromOverloadList)
36  error(IO.mapStringZ(Method.Name, "Name"));
37 
38  return Error::success();
39  }
40 
41 private:
42  bool IsFromOverloadList;
43 };
44 }
45 
47  StringRef &UniqueName, bool HasUniqueName) {
48  if (IO.isWriting()) {
49  // Try to be smart about what we write here. We can't write anything too
50  // large, so if we're going to go over the limit, truncate both the name
51  // and unique name by the same amount.
52  size_t BytesLeft = IO.maxFieldLength();
53  if (HasUniqueName) {
54  size_t BytesNeeded = Name.size() + UniqueName.size() + 2;
55  StringRef N = Name;
56  StringRef U = UniqueName;
57  if (BytesNeeded > BytesLeft) {
58  size_t BytesToDrop = (BytesNeeded - BytesLeft);
59  size_t DropN = std::min(N.size(), BytesToDrop / 2);
60  size_t DropU = std::min(U.size(), BytesToDrop - DropN);
61 
62  N = N.drop_back(DropN);
63  U = U.drop_back(DropU);
64  }
65 
66  error(IO.mapStringZ(N));
67  error(IO.mapStringZ(U));
68  } else {
69  // Cap the length of the string at however many bytes we have available,
70  // plus one for the required null terminator.
71  auto N = StringRef(Name).take_front(BytesLeft - 1);
72  error(IO.mapStringZ(N));
73  }
74  } else {
75  // Reading & Streaming mode come after writing mode is executed for each
76  // record. Truncating large names are done during writing, so its not
77  // necessary to do it while reading or streaming.
78  error(IO.mapStringZ(Name, "Name"));
79  if (HasUniqueName)
80  error(IO.mapStringZ(UniqueName, "LinkageName"));
81  }
82 
83  return Error::success();
84 }
85 
87  switch (LT) {
88 #define TYPE_RECORD(ename, value, name) \
89  case ename: \
90  return #ename;
91 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
92  default:
93  break;
94  }
95  return "UnknownLeaf";
96 }
97 
99  assert(!TypeKind.hasValue() && "Already in a type mapping!");
100  assert(!MemberKind.hasValue() && "Already in a member mapping!");
101 
102  // FieldList and MethodList records can be any length because they can be
103  // split with continuation records. All other record types cannot be
104  // longer than the maximum record length.
105  Optional<uint32_t> MaxLen;
106  if (CVR.kind() != TypeLeafKind::LF_FIELDLIST &&
107  CVR.kind() != TypeLeafKind::LF_METHODLIST)
108  MaxLen = MaxRecordLength - sizeof(RecordPrefix);
109  error(IO.beginRecord(MaxLen));
110  TypeKind = CVR.kind();
111  return Error::success();
112 }
113 
115  return visitTypeBegin(CVR);
116 }
117 
119  assert(TypeKind.hasValue() && "Not in a type mapping!");
120  assert(!MemberKind.hasValue() && "Still in a member mapping!");
121 
122  error(IO.endRecord());
123 
124  TypeKind.reset();
125  return Error::success();
126 }
127 
129  assert(TypeKind.hasValue() && "Not in a type mapping!");
130  assert(!MemberKind.hasValue() && "Already in a member mapping!");
131 
132  // The largest possible subrecord is one in which there is a record prefix,
133  // followed by the subrecord, followed by a continuation, and that entire
134  // sequence spaws `MaxRecordLength` bytes. So the record's length is
135  // calculated as follows.
136 
137  constexpr uint32_t ContinuationLength = 8;
138  error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) -
139  ContinuationLength));
140 
141  MemberKind = Record.Kind;
142  if (IO.isStreaming()) {
143  error(IO.mapEnum(Record.Kind,
144  "Member kind: " + getLeafTypeName(Record.Kind)));
145  }
146  return Error::success();
147 }
148 
150  assert(TypeKind.hasValue() && "Not in a type mapping!");
151  assert(MemberKind.hasValue() && "Not in a member mapping!");
152 
153  if (IO.isReading()) {
154  if (auto EC = IO.skipPadding())
155  return EC;
156  }
157 
158  MemberKind.reset();
159  error(IO.endRecord());
160  return Error::success();
161 }
162 
164  error(IO.mapInteger(Record.ModifiedType, "ModifiedType"));
165  error(IO.mapEnum(Record.Modifiers, "Modifiers"));
166  return Error::success();
167 }
168 
170  ProcedureRecord &Record) {
171  error(IO.mapInteger(Record.ReturnType, "ReturnType"));
172  error(IO.mapEnum(Record.CallConv, "CallingConvention"));
173  error(IO.mapEnum(Record.Options, "FunctionOptions"));
174  error(IO.mapInteger(Record.ParameterCount, "NumParameters"));
175  error(IO.mapInteger(Record.ArgumentList, "ArgListType"));
176 
177  return Error::success();
178 }
179 
181  MemberFunctionRecord &Record) {
182  error(IO.mapInteger(Record.ReturnType, "ReturnType"));
183  error(IO.mapInteger(Record.ClassType, "ClassType"));
184  error(IO.mapInteger(Record.ThisType, "ThisType"));
185  error(IO.mapEnum(Record.CallConv, "CallingConvention"));
186  error(IO.mapEnum(Record.Options, "FunctionOptions"));
187  error(IO.mapInteger(Record.ParameterCount, "NumParameters"));
188  error(IO.mapInteger(Record.ArgumentList, "ArgListType"));
189  error(IO.mapInteger(Record.ThisPointerAdjustment, "ThisAdjustment"));
190 
191  return Error::success();
192 }
193 
195  error(IO.mapVectorN<uint32_t>(
196  Record.ArgIndices,
197  [](CodeViewRecordIO &IO, TypeIndex &N) {
198  return IO.mapInteger(N, "Argument");
199  },
200  "NumArgs"));
201  return Error::success();
202 }
203 
205  StringListRecord &Record) {
206  error(IO.mapVectorN<uint32_t>(
207  Record.StringIndices,
208  [](CodeViewRecordIO &IO, TypeIndex &N) {
209  return IO.mapInteger(N, "Strings");
210  },
211  "NumStrings"));
212 
213  return Error::success();
214 }
215 
217  error(IO.mapInteger(Record.ReferentType, "PointeeType"));
218  error(IO.mapInteger(Record.Attrs, "Attributes"));
219 
220  if (Record.isPointerToMember()) {
221  if (IO.isReading())
222  Record.MemberInfo.emplace();
223 
224  MemberPointerInfo &M = *Record.MemberInfo;
225  error(IO.mapInteger(M.ContainingType, "ClassType"));
226  error(IO.mapEnum(M.Representation, "Representation"));
227  }
228 
229  return Error::success();
230 }
231 
233  error(IO.mapInteger(Record.ElementType, "ElementType"));
234  error(IO.mapInteger(Record.IndexType, "IndexType"));
235  error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
236  error(IO.mapStringZ(Record.Name, "Name"));
237 
238  return Error::success();
239 }
240 
242  assert((CVR.kind() == TypeLeafKind::LF_STRUCTURE) ||
243  (CVR.kind() == TypeLeafKind::LF_CLASS) ||
244  (CVR.kind() == TypeLeafKind::LF_INTERFACE));
245 
246  error(IO.mapInteger(Record.MemberCount, "MemberCount"));
247  error(IO.mapEnum(Record.Options, "Properties"));
248  error(IO.mapInteger(Record.FieldList, "FieldList"));
249  error(IO.mapInteger(Record.DerivationList, "DerivedFrom"));
250  error(IO.mapInteger(Record.VTableShape, "VShape"));
251  error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
252  error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
253  Record.hasUniqueName()));
254 
255  return Error::success();
256 }
257 
259  error(IO.mapInteger(Record.MemberCount, "MemberCount"));
260  error(IO.mapEnum(Record.Options, "Properties"));
261  error(IO.mapInteger(Record.FieldList, "FieldList"));
262  error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
263  error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
264  Record.hasUniqueName()));
265 
266  return Error::success();
267 }
268 
270  error(IO.mapInteger(Record.MemberCount, "NumEnumerators"));
271  error(IO.mapEnum(Record.Options, "Properties"));
272  error(IO.mapInteger(Record.UnderlyingType, "UnderlyingType"));
273  error(IO.mapInteger(Record.FieldList, "FieldListType"));
274  error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
275  Record.hasUniqueName()));
276 
277  return Error::success();
278 }
279 
281  error(IO.mapInteger(Record.Type, "Type"));
282  error(IO.mapInteger(Record.BitSize, "BitSize"));
283  error(IO.mapInteger(Record.BitOffset, "BitOffset"));
284 
285  return Error::success();
286 }
287 
289  VFTableShapeRecord &Record) {
290  uint16_t Size;
291  if (!IO.isReading()) {
292  ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
293  Size = Slots.size();
294  error(IO.mapInteger(Size, "VFEntryCount"));
295 
296  for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
297  uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
298  if ((SlotIndex + 1) < Slots.size()) {
299  Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
300  }
301  error(IO.mapInteger(Byte));
302  }
303  } else {
304  error(IO.mapInteger(Size));
305  for (uint16_t I = 0; I < Size; I += 2) {
306  uint8_t Byte;
307  error(IO.mapInteger(Byte));
308  Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte & 0xF));
309  if ((I + 1) < Size)
310  Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte >> 4));
311  }
312  }
313 
314  return Error::success();
315 }
316 
318  error(IO.mapInteger(Record.CompleteClass, "CompleteClass"));
319  error(IO.mapInteger(Record.OverriddenVFTable, "OverriddenVFTable"));
320  error(IO.mapInteger(Record.VFPtrOffset, "VFPtrOffset"));
321  uint32_t NamesLen = 0;
322  if (!IO.isReading()) {
323  for (auto Name : Record.MethodNames)
324  NamesLen += Name.size() + 1;
325  }
326  error(IO.mapInteger(NamesLen));
327  error(IO.mapVectorTail(
328  Record.MethodNames,
329  [](CodeViewRecordIO &IO, StringRef &S) {
330  return IO.mapStringZ(S, "MethodName");
331  },
332  "VFTableName"));
333 
334  return Error::success();
335 }
336 
338  error(IO.mapInteger(Record.Id, "Id"));
339  error(IO.mapStringZ(Record.String, "StringData"));
340 
341  return Error::success();
342 }
343 
345  UdtSourceLineRecord &Record) {
346  error(IO.mapInteger(Record.UDT, "UDT"));
347  error(IO.mapInteger(Record.SourceFile, "SourceFile"));
348  error(IO.mapInteger(Record.LineNumber, "LineNumber"));
349 
350  return Error::success();
351 }
352 
354  UdtModSourceLineRecord &Record) {
355  error(IO.mapInteger(Record.UDT, "UDT"));
356  error(IO.mapInteger(Record.SourceFile, "SourceFile"));
357  error(IO.mapInteger(Record.LineNumber, "LineNumber"));
358  error(IO.mapInteger(Record.Module, "Module"));
359 
360  return Error::success();
361 }
362 
364  error(IO.mapInteger(Record.ParentScope, "ParentScope"));
365  error(IO.mapInteger(Record.FunctionType, "FunctionType"));
366  error(IO.mapStringZ(Record.Name, "Name"));
367 
368  return Error::success();
369 }
370 
372  MemberFuncIdRecord &Record) {
373  error(IO.mapInteger(Record.ClassType, "ClassType"));
374  error(IO.mapInteger(Record.FunctionType, "FunctionType"));
375  error(IO.mapStringZ(Record.Name, "Name"));
376 
377  return Error::success();
378 }
379 
381  BuildInfoRecord &Record) {
382  error(IO.mapVectorN<uint16_t>(
383  Record.ArgIndices,
384  [](CodeViewRecordIO &IO, TypeIndex &N) {
385  return IO.mapInteger(N, "Argument");
386  },
387  "NumArgs"));
388 
389  return Error::success();
390 }
391 
393  MethodOverloadListRecord &Record) {
394  // TODO: Split the list into multiple records if it's longer than 64KB, using
395  // a subrecord of TypeRecordKind::Index to chain the records together.
396  error(IO.mapVectorTail(Record.Methods, MapOneMethodRecord(true), "Method"));
397 
398  return Error::success();
399 }
400 
402  FieldListRecord &Record) {
403  if (IO.isStreaming()) {
404  if (auto EC = codeview::visitMemberRecordStream(Record.Data, *this))
405  return EC;
406  } else
407  error(IO.mapByteVectorTail(Record.Data));
408 
409  return Error::success();
410 }
411 
413  TypeServer2Record &Record) {
414  error(IO.mapGuid(Record.Guid, "Guid"));
415  error(IO.mapInteger(Record.Age, "Age"));
416  error(IO.mapStringZ(Record.Name, "Name"));
417  return Error::success();
418 }
419 
421  error(IO.mapEnum(Record.Mode, "Mode"));
422  return Error::success();
423 }
424 
426  BaseClassRecord &Record) {
427  error(IO.mapInteger(Record.Attrs.Attrs, "AccessSpecifier"));
428  error(IO.mapInteger(Record.Type, "BaseType"));
429  error(IO.mapEncodedInteger(Record.Offset, "BaseOffset"));
430 
431  return Error::success();
432 }
433 
435  EnumeratorRecord &Record) {
436  error(IO.mapInteger(Record.Attrs.Attrs));
437 
438  // FIXME: Handle full APInt such as __int128.
439  error(IO.mapEncodedInteger(Record.Value, "EnumValue"));
440  error(IO.mapStringZ(Record.Name, "Name"));
441 
442  return Error::success();
443 }
444 
446  DataMemberRecord &Record) {
447  error(IO.mapInteger(Record.Attrs.Attrs, "AccessSpecifier"));
448  error(IO.mapInteger(Record.Type, "Type"));
449  error(IO.mapEncodedInteger(Record.FieldOffset, "FieldOffset"));
450  error(IO.mapStringZ(Record.Name, "Name"));
451 
452  return Error::success();
453 }
454 
456  OverloadedMethodRecord &Record) {
457  error(IO.mapInteger(Record.NumOverloads, "MethodCount"));
458  error(IO.mapInteger(Record.MethodList, "MethodListIndex"));
459  error(IO.mapStringZ(Record.Name, "Name"));
460 
461  return Error::success();
462 }
463 
465  OneMethodRecord &Record) {
466  const bool IsFromOverloadList = (TypeKind == LF_METHODLIST);
467  MapOneMethodRecord Mapper(IsFromOverloadList);
468  return Mapper(IO, Record);
469 }
470 
472  NestedTypeRecord &Record) {
473  uint16_t Padding = 0;
474  error(IO.mapInteger(Padding, "Padding"));
475  error(IO.mapInteger(Record.Type, "Type"));
476  error(IO.mapStringZ(Record.Name, "Name"));
477 
478  return Error::success();
479 }
480 
482  StaticDataMemberRecord &Record) {
483 
484  error(IO.mapInteger(Record.Attrs.Attrs, "AccessSpecifier"));
485  error(IO.mapInteger(Record.Type, "Type"));
486  error(IO.mapStringZ(Record.Name, "Name"));
487 
488  return Error::success();
489 }
490 
492  VirtualBaseClassRecord &Record) {
493 
494  error(IO.mapInteger(Record.Attrs.Attrs, "AccessSpecifier"));
495  error(IO.mapInteger(Record.BaseType, "BaseType"));
496  error(IO.mapInteger(Record.VBPtrType, "VBPtrType"));
497  error(IO.mapEncodedInteger(Record.VBPtrOffset, "VBPtrOffset"));
498  error(IO.mapEncodedInteger(Record.VTableIndex, "VBTableIndex"));
499 
500  return Error::success();
501 }
502 
504  VFPtrRecord &Record) {
505  uint16_t Padding = 0;
506  error(IO.mapInteger(Padding, "Padding"));
507  error(IO.mapInteger(Record.Type, "Type"));
508 
509  return Error::success();
510 }
511 
513  ListContinuationRecord &Record) {
514  uint16_t Padding = 0;
515  error(IO.mapInteger(Padding, "Padding"));
516  error(IO.mapInteger(Record.ContinuationIndex, "ContinuationIndex"));
517 
518  return Error::success();
519 }
520 
522  PrecompRecord &Precomp) {
523  error(IO.mapInteger(Precomp.StartTypeIndex, "StartIndex"));
524  error(IO.mapInteger(Precomp.TypesCount, "Count"));
525  error(IO.mapInteger(Precomp.Signature, "Signature"));
526  error(IO.mapStringZ(Precomp.PrecompFilePath, "PrecompFile"));
527  return Error::success();
528 }
529 
531  EndPrecompRecord &EndPrecomp) {
532  error(IO.mapInteger(EndPrecomp.Signature, "Signature"));
533  return Error::success();
534 }
LLVM_NODISCARD StringRef take_front(size_t N=1) const
Return a StringRef equal to &#39;this&#39; but with only the first N elements remaining.
Definition: StringRef.h:587
Kind kind() const
Definition: CVRecord.h:43
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
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
#define error(X)
ArrayRef< uint8_t > Data
Definition: TypeRecord.h:397
Error visitMemberRecordStream(ArrayRef< uint8_t > FieldList, TypeVisitorCallbacks &Callbacks)
Error visitMemberEnd(CVMemberRecord &Record) override
bool hasUniqueName() const
Definition: TypeRecord.h:436
Error visitTypeEnd(CVType &Record) override
static Error visitKnownRecord(CVSymbol &Record, SymbolVisitorCallbacks &Callbacks)
Error visitTypeBegin(CVType &Record) override
Paired begin/end actions for all types.
A 32-bit type reference.
Definition: TypeIndex.h:95
LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:130
std::vector< TypeIndex > StringIndices
Definition: TypeRecord.h:265
* if(!EatIfPresent(lltok::kw_thread_local)) return false
ParseOptionalThreadLocal := /*empty.
static Error visitKnownMember(CVMemberRecord &Record, TypeVisitorCallbacks &Callbacks)
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:148
Optional< MemberPointerInfo > MemberInfo
Definition: TypeRecord.h:355
LF_INDEX - Used to chain two large LF_FIELDLIST or LF_METHODLIST records together.
Definition: TypeRecord.h:920
std::vector< TypeIndex > ArgIndices
Definition: TypeRecord.h:251
For method overload sets. LF_METHOD.
Definition: TypeRecord.h:770
std::vector< StringRef > MethodNames
Definition: TypeRecord.h:721
static constexpr uint32_t ContinuationLength
Error mapInteger(TypeIndex &TypeInd, const Twine &Comment="")
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name, StringRef &UniqueName, bool HasUniqueName)
CallingConvention CallConv
Definition: TypeRecord.h:169
Error mapStringZ(StringRef &Value, const Twine &Comment="")
std::vector< OneMethodRecord > Methods
Definition: TypeRecord.h:766
static StringRef getLeafTypeName(TypeLeafKind LT)
#define I(x, y, z)
Definition: MD5.cpp:58
#define N
uint32_t Size
Definition: Profile.cpp:46
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
std::vector< VFTableSlotKind > Slots
Definition: TypeRecord.h:576
ArrayRef< VFTableSlotKind > getSlots() const
Definition: TypeRecord.h:567
LLVM_NODISCARD StringRef drop_back(size_t N=1) const
Return a StringRef equal to &#39;this&#39; but with the last N elements dropped.
Definition: StringRef.h:628
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
SlotIndex - An opaque wrapper around machine indexes.
Definition: SlotIndexes.h:83
SmallVector< TypeIndex, MaxArgs > ArgIndices
Definition: TypeRecord.h:692
Error visitMemberBegin(CVMemberRecord &Record) override
PointerToMemberRepresentation Representation
Definition: TypeRecord.h:120