Line data Source code
1 : //===- TypeRecordMapping.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 :
10 : #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
11 :
12 : using namespace llvm;
13 : using namespace llvm::codeview;
14 :
15 : #define error(X) \
16 : if (auto EC = X) \
17 : return EC;
18 :
19 : namespace {
20 : struct MapOneMethodRecord {
21 : explicit MapOneMethodRecord(bool IsFromOverloadList)
22 881 : : IsFromOverloadList(IsFromOverloadList) {}
23 :
24 0 : Error operator()(CodeViewRecordIO &IO, OneMethodRecord &Method) const {
25 0 : error(IO.mapInteger(Method.Attrs.Attrs));
26 0 : if (IsFromOverloadList) {
27 0 : uint16_t Padding = 0;
28 0 : error(IO.mapInteger(Padding));
29 : }
30 0 : error(IO.mapInteger(Method.Type));
31 : if (Method.isIntroducingVirtual()) {
32 0 : error(IO.mapInteger(Method.VFTableOffset));
33 0 : } else if (!IO.isWriting())
34 0 : Method.VFTableOffset = -1;
35 :
36 0 : if (!IsFromOverloadList)
37 0 : error(IO.mapStringZ(Method.Name));
38 :
39 : return Error::success();
40 : }
41 :
42 : private:
43 : bool IsFromOverloadList;
44 : };
45 : }
46 :
47 3514 : static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name,
48 : StringRef &UniqueName, bool HasUniqueName) {
49 3514 : if (IO.isWriting()) {
50 : // Try to be smart about what we write here. We can't write anything too
51 : // large, so if we're going to go over the limit, truncate both the name
52 : // and unique name by the same amount.
53 415 : size_t BytesLeft = IO.maxFieldLength();
54 415 : if (HasUniqueName) {
55 355 : size_t BytesNeeded = Name.size() + UniqueName.size() + 2;
56 355 : StringRef N = Name;
57 355 : StringRef U = UniqueName;
58 355 : if (BytesNeeded > BytesLeft) {
59 3 : size_t BytesToDrop = (BytesNeeded - BytesLeft);
60 3 : size_t DropN = std::min(N.size(), BytesToDrop / 2);
61 6 : size_t DropU = std::min(U.size(), BytesToDrop - DropN);
62 :
63 3 : N = N.drop_back(DropN);
64 3 : U = U.drop_back(DropU);
65 : }
66 :
67 710 : error(IO.mapStringZ(N));
68 710 : error(IO.mapStringZ(U));
69 : } else {
70 : // Cap the length of the string at however many bytes we have available,
71 : // plus one for the required null terminator.
72 60 : auto N = StringRef(Name).take_front(BytesLeft - 1);
73 120 : error(IO.mapStringZ(N));
74 : }
75 : } else {
76 6198 : error(IO.mapStringZ(Name));
77 3099 : if (HasUniqueName)
78 6002 : error(IO.mapStringZ(UniqueName));
79 : }
80 :
81 : return Error::success();
82 : }
83 :
84 16329 : Error TypeRecordMapping::visitTypeBegin(CVType &CVR) {
85 : assert(!TypeKind.hasValue() && "Already in a type mapping!");
86 : assert(!MemberKind.hasValue() && "Already in a member mapping!");
87 :
88 : // FieldList and MethodList records can be any length because they can be
89 : // split with continuation records. All other record types cannot be
90 : // longer than the maximum record length.
91 : Optional<uint32_t> MaxLen;
92 16329 : if (CVR.Type != TypeLeafKind::LF_FIELDLIST &&
93 : CVR.Type != TypeLeafKind::LF_METHODLIST)
94 : MaxLen = MaxRecordLength - sizeof(RecordPrefix);
95 30139 : error(IO.beginRecord(MaxLen));
96 16329 : TypeKind = CVR.Type;
97 : return Error::success();
98 : }
99 :
100 16327 : Error TypeRecordMapping::visitTypeEnd(CVType &Record) {
101 : assert(TypeKind.hasValue() && "Not in a type mapping!");
102 : assert(!MemberKind.hasValue() && "Still in a member mapping!");
103 :
104 32654 : error(IO.endRecord());
105 :
106 : TypeKind.reset();
107 : return Error::success();
108 : }
109 :
110 15879 : Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) {
111 : assert(TypeKind.hasValue() && "Not in a type mapping!");
112 : assert(!MemberKind.hasValue() && "Already in a member mapping!");
113 :
114 : // The largest possible subrecord is one in which there is a record prefix,
115 : // followed by the subrecord, followed by a continuation, and that entire
116 : // sequence spaws `MaxRecordLength` bytes. So the record's length is
117 : // calculated as follows.
118 : constexpr uint32_t ContinuationLength = 8;
119 31758 : error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) -
120 : ContinuationLength));
121 :
122 15879 : MemberKind = Record.Kind;
123 : return Error::success();
124 : }
125 :
126 15879 : Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) {
127 : assert(TypeKind.hasValue() && "Not in a type mapping!");
128 : assert(MemberKind.hasValue() && "Not in a member mapping!");
129 :
130 15879 : if (!IO.isWriting()) {
131 18444 : if (auto EC = IO.skipPadding())
132 : return EC;
133 : }
134 :
135 : MemberKind.reset();
136 31758 : error(IO.endRecord());
137 : return Error::success();
138 : }
139 :
140 305 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ModifierRecord &Record) {
141 610 : error(IO.mapInteger(Record.ModifiedType));
142 610 : error(IO.mapEnum(Record.Modifiers));
143 :
144 : return Error::success();
145 : }
146 :
147 755 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
148 : ProcedureRecord &Record) {
149 1510 : error(IO.mapInteger(Record.ReturnType));
150 1510 : error(IO.mapEnum(Record.CallConv));
151 1510 : error(IO.mapEnum(Record.Options));
152 1510 : error(IO.mapInteger(Record.ParameterCount));
153 1510 : error(IO.mapInteger(Record.ArgumentList));
154 :
155 : return Error::success();
156 : }
157 :
158 1744 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
159 : MemberFunctionRecord &Record) {
160 3488 : error(IO.mapInteger(Record.ReturnType));
161 3488 : error(IO.mapInteger(Record.ClassType));
162 3488 : error(IO.mapInteger(Record.ThisType));
163 3488 : error(IO.mapEnum(Record.CallConv));
164 3488 : error(IO.mapEnum(Record.Options));
165 3488 : error(IO.mapInteger(Record.ParameterCount));
166 3488 : error(IO.mapInteger(Record.ArgumentList));
167 3488 : error(IO.mapInteger(Record.ThisPointerAdjustment));
168 :
169 : return Error::success();
170 : }
171 :
172 1400 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) {
173 2800 : error(IO.mapVectorN<uint32_t>(
174 : Record.ArgIndices,
175 : [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
176 :
177 : return Error::success();
178 : }
179 :
180 87 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
181 : StringListRecord &Record) {
182 174 : error(IO.mapVectorN<uint32_t>(
183 : Record.StringIndices,
184 : [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
185 :
186 : return Error::success();
187 : }
188 :
189 1676 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) {
190 3352 : error(IO.mapInteger(Record.ReferentType));
191 3352 : error(IO.mapInteger(Record.Attrs));
192 :
193 : if (Record.isPointerToMember()) {
194 55 : if (!IO.isWriting())
195 : Record.MemberInfo.emplace();
196 :
197 : MemberPointerInfo &M = *Record.MemberInfo;
198 110 : error(IO.mapInteger(M.ContainingType));
199 110 : error(IO.mapEnum(M.Representation));
200 : }
201 :
202 : return Error::success();
203 : }
204 :
205 182 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) {
206 364 : error(IO.mapInteger(Record.ElementType));
207 364 : error(IO.mapInteger(Record.IndexType));
208 364 : error(IO.mapEncodedInteger(Record.Size));
209 364 : error(IO.mapStringZ(Record.Name));
210 :
211 : return Error::success();
212 : }
213 :
214 2916 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) {
215 : assert((CVR.Type == TypeLeafKind::LF_STRUCTURE) ||
216 : (CVR.Type == TypeLeafKind::LF_CLASS) ||
217 : (CVR.Type == TypeLeafKind::LF_INTERFACE));
218 :
219 5832 : error(IO.mapInteger(Record.MemberCount));
220 5832 : error(IO.mapEnum(Record.Options));
221 5832 : error(IO.mapInteger(Record.FieldList));
222 5832 : error(IO.mapInteger(Record.DerivationList));
223 5832 : error(IO.mapInteger(Record.VTableShape));
224 5832 : error(IO.mapEncodedInteger(Record.Size));
225 8748 : error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
226 : Record.hasUniqueName()));
227 :
228 : return Error::success();
229 : }
230 :
231 71 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) {
232 142 : error(IO.mapInteger(Record.MemberCount));
233 142 : error(IO.mapEnum(Record.Options));
234 142 : error(IO.mapInteger(Record.FieldList));
235 142 : error(IO.mapEncodedInteger(Record.Size));
236 213 : error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
237 : Record.hasUniqueName()));
238 :
239 : return Error::success();
240 : }
241 :
242 527 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) {
243 1054 : error(IO.mapInteger(Record.MemberCount));
244 1054 : error(IO.mapEnum(Record.Options));
245 1054 : error(IO.mapInteger(Record.UnderlyingType));
246 1054 : error(IO.mapInteger(Record.FieldList));
247 1581 : error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
248 : Record.hasUniqueName()));
249 :
250 : return Error::success();
251 : }
252 :
253 32 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) {
254 64 : error(IO.mapInteger(Record.Type));
255 64 : error(IO.mapInteger(Record.BitSize));
256 64 : error(IO.mapInteger(Record.BitOffset));
257 :
258 : return Error::success();
259 : }
260 :
261 56 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
262 : VFTableShapeRecord &Record) {
263 : uint16_t Size;
264 56 : if (IO.isWriting()) {
265 : ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
266 17 : Size = Slots.size();
267 34 : error(IO.mapInteger(Size));
268 :
269 32 : for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
270 15 : uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
271 15 : if ((SlotIndex + 1) < Slots.size()) {
272 2 : Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
273 : }
274 15 : error(IO.mapInteger(Byte));
275 : }
276 : } else {
277 78 : error(IO.mapInteger(Size));
278 80 : for (uint16_t I = 0; I < Size; I += 2) {
279 : uint8_t Byte;
280 82 : error(IO.mapInteger(Byte));
281 41 : Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte & 0xF));
282 41 : if ((I + 1) < Size)
283 12 : Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte >> 4));
284 : }
285 : }
286 :
287 : return Error::success();
288 : }
289 :
290 17 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR, VFTableRecord &Record) {
291 34 : error(IO.mapInteger(Record.CompleteClass));
292 34 : error(IO.mapInteger(Record.OverriddenVFTable));
293 34 : error(IO.mapInteger(Record.VFPtrOffset));
294 17 : uint32_t NamesLen = 0;
295 17 : if (IO.isWriting()) {
296 16 : for (auto Name : Record.MethodNames)
297 10 : NamesLen += Name.size() + 1;
298 : }
299 34 : error(IO.mapInteger(NamesLen));
300 34 : error(IO.mapVectorTail(
301 : Record.MethodNames,
302 : [](CodeViewRecordIO &IO, StringRef &S) { return IO.mapStringZ(S); }));
303 :
304 : return Error::success();
305 : }
306 :
307 1651 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) {
308 3302 : error(IO.mapInteger(Record.Id));
309 3302 : error(IO.mapStringZ(Record.String));
310 :
311 : return Error::success();
312 : }
313 :
314 945 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
315 : UdtSourceLineRecord &Record) {
316 1890 : error(IO.mapInteger(Record.UDT));
317 1890 : error(IO.mapInteger(Record.SourceFile));
318 1890 : error(IO.mapInteger(Record.LineNumber));
319 :
320 : return Error::success();
321 : }
322 :
323 52 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
324 : UdtModSourceLineRecord &Record) {
325 104 : error(IO.mapInteger(Record.UDT));
326 104 : error(IO.mapInteger(Record.SourceFile));
327 104 : error(IO.mapInteger(Record.LineNumber));
328 104 : error(IO.mapInteger(Record.Module));
329 :
330 : return Error::success();
331 : }
332 :
333 761 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) {
334 1522 : error(IO.mapInteger(Record.ParentScope));
335 1522 : error(IO.mapInteger(Record.FunctionType));
336 1522 : error(IO.mapStringZ(Record.Name));
337 :
338 : return Error::success();
339 : }
340 :
341 171 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
342 : MemberFuncIdRecord &Record) {
343 342 : error(IO.mapInteger(Record.ClassType));
344 342 : error(IO.mapInteger(Record.FunctionType));
345 342 : error(IO.mapStringZ(Record.Name));
346 :
347 : return Error::success();
348 : }
349 :
350 433 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
351 : BuildInfoRecord &Record) {
352 866 : error(IO.mapVectorN<uint16_t>(
353 : Record.ArgIndices,
354 : [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
355 :
356 : return Error::success();
357 : }
358 :
359 368 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
360 : MethodOverloadListRecord &Record) {
361 : // TODO: Split the list into multiple records if it's longer than 64KB, using
362 : // a subrecord of TypeRecordKind::Index to chain the records together.
363 368 : error(IO.mapVectorTail(Record.Methods, MapOneMethodRecord(true)));
364 :
365 : return Error::success();
366 : }
367 :
368 1004 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
369 : FieldListRecord &Record) {
370 2008 : error(IO.mapByteVectorTail(Record.Data));
371 :
372 : return Error::success();
373 : }
374 :
375 20 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
376 : TypeServer2Record &Record) {
377 40 : error(IO.mapGuid(Record.Guid));
378 40 : error(IO.mapInteger(Record.Age));
379 40 : error(IO.mapStringZ(Record.Name));
380 : return Error::success();
381 : }
382 :
383 1 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR, LabelRecord &Record) {
384 2 : error(IO.mapEnum(Record.Mode));
385 : return Error::success();
386 : }
387 :
388 48 : Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
389 : BaseClassRecord &Record) {
390 96 : error(IO.mapInteger(Record.Attrs.Attrs));
391 96 : error(IO.mapInteger(Record.Type));
392 96 : error(IO.mapEncodedInteger(Record.Offset));
393 :
394 : return Error::success();
395 : }
396 :
397 13034 : Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
398 : EnumeratorRecord &Record) {
399 26068 : error(IO.mapInteger(Record.Attrs.Attrs));
400 :
401 : // FIXME: Handle full APInt such as __int128.
402 26068 : error(IO.mapEncodedInteger(Record.Value));
403 26068 : error(IO.mapStringZ(Record.Name));
404 :
405 : return Error::success();
406 : }
407 :
408 1465 : Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
409 : DataMemberRecord &Record) {
410 2930 : error(IO.mapInteger(Record.Attrs.Attrs));
411 2930 : error(IO.mapInteger(Record.Type));
412 2930 : error(IO.mapEncodedInteger(Record.FieldOffset));
413 2930 : error(IO.mapStringZ(Record.Name));
414 :
415 : return Error::success();
416 : }
417 :
418 281 : Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
419 : OverloadedMethodRecord &Record) {
420 562 : error(IO.mapInteger(Record.NumOverloads));
421 562 : error(IO.mapInteger(Record.MethodList));
422 562 : error(IO.mapStringZ(Record.Name));
423 :
424 : return Error::success();
425 : }
426 :
427 513 : Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
428 : OneMethodRecord &Record) {
429 : const bool IsFromOverloadList = (TypeKind == LF_METHODLIST);
430 : MapOneMethodRecord Mapper(IsFromOverloadList);
431 513 : return Mapper(IO, Record);
432 : }
433 :
434 244 : Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
435 : NestedTypeRecord &Record) {
436 244 : uint16_t Padding = 0;
437 488 : error(IO.mapInteger(Padding));
438 488 : error(IO.mapInteger(Record.Type));
439 488 : error(IO.mapStringZ(Record.Name));
440 :
441 : return Error::success();
442 : }
443 :
444 127 : Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
445 : StaticDataMemberRecord &Record) {
446 :
447 254 : error(IO.mapInteger(Record.Attrs.Attrs));
448 254 : error(IO.mapInteger(Record.Type));
449 254 : error(IO.mapStringZ(Record.Name));
450 :
451 : return Error::success();
452 : }
453 :
454 34 : Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
455 : VirtualBaseClassRecord &Record) {
456 :
457 68 : error(IO.mapInteger(Record.Attrs.Attrs));
458 68 : error(IO.mapInteger(Record.BaseType));
459 68 : error(IO.mapInteger(Record.VBPtrType));
460 68 : error(IO.mapEncodedInteger(Record.VBPtrOffset));
461 68 : error(IO.mapEncodedInteger(Record.VTableIndex));
462 :
463 : return Error::success();
464 : }
465 :
466 37 : Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
467 : VFPtrRecord &Record) {
468 37 : uint16_t Padding = 0;
469 74 : error(IO.mapInteger(Padding));
470 74 : error(IO.mapInteger(Record.Type));
471 :
472 : return Error::success();
473 : }
474 :
475 6 : Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
476 : ListContinuationRecord &Record) {
477 6 : uint16_t Padding = 0;
478 12 : error(IO.mapInteger(Padding));
479 12 : error(IO.mapInteger(Record.ContinuationIndex));
480 :
481 : return Error::success();
482 : }
483 :
484 4 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
485 : PrecompRecord &Precomp) {
486 8 : error(IO.mapInteger(Precomp.StartTypeIndex));
487 8 : error(IO.mapInteger(Precomp.TypesCount));
488 8 : error(IO.mapInteger(Precomp.Signature));
489 8 : error(IO.mapStringZ(Precomp.PrecompFilePath));
490 : return Error::success();
491 : }
492 :
493 4 : Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
494 : EndPrecompRecord &EndPrecomp) {
495 8 : error(IO.mapInteger(EndPrecomp.Signature));
496 : return Error::success();
497 : }
|