1 //===- SymbolRecord.h -------------------------------------------*- 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 
9 #ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H
10 #define LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H
11 
12 #include "llvm/ADT/APSInt.h"
13 #include "llvm/ADT/ArrayRef.h"
14 #include "llvm/ADT/Optional.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/ADT/iterator.h"
17 #include "llvm/ADT/iterator_range.h"
18 #include "llvm/DebugInfo/CodeView/CVRecord.h"
19 #include "llvm/DebugInfo/CodeView/CodeView.h"
20 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
21 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
22 #include "llvm/Support/BinaryStreamArray.h"
23 #include "llvm/Support/Endian.h"
24 #include <cstdint>
25 #include <vector>
26 
27 namespace llvm {
28 namespace codeview {
29 
30 class SymbolRecord {
31 protected:
SymbolRecord(SymbolRecordKind Kind)32   explicit SymbolRecord(SymbolRecordKind Kind) : Kind(Kind) {}
33 
34 public:
getKind()35   SymbolRecordKind getKind() const { return Kind; }
36 
37   SymbolRecordKind Kind;
38 };
39 
40 // S_GPROC32, S_LPROC32, S_GPROC32_ID, S_LPROC32_ID, S_LPROC32_DPC or
41 // S_LPROC32_DPC_ID
42 class ProcSym : public SymbolRecord {
43   static constexpr uint32_t RelocationOffset = 32;
44 
45 public:
ProcSym(SymbolRecordKind Kind)46   explicit ProcSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
ProcSym(SymbolRecordKind Kind,uint32_t RecordOffset)47   ProcSym(SymbolRecordKind Kind, uint32_t RecordOffset)
48       : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
49 
getRelocationOffset()50   uint32_t getRelocationOffset() const {
51     return RecordOffset + RelocationOffset;
52   }
53 
54   uint32_t Parent = 0;
55   uint32_t End = 0;
56   uint32_t Next = 0;
57   uint32_t CodeSize = 0;
58   uint32_t DbgStart = 0;
59   uint32_t DbgEnd = 0;
60   TypeIndex FunctionType;
61   uint32_t CodeOffset = 0;
62   uint16_t Segment = 0;
63   ProcSymFlags Flags = ProcSymFlags::None;
64   StringRef Name;
65 
66   uint32_t RecordOffset = 0;
67 };
68 
69 // S_THUNK32
70 class Thunk32Sym : public SymbolRecord {
71 public:
Thunk32Sym(SymbolRecordKind Kind)72   explicit Thunk32Sym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
Thunk32Sym(SymbolRecordKind Kind,uint32_t RecordOffset)73   Thunk32Sym(SymbolRecordKind Kind, uint32_t RecordOffset)
74       : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
75 
76   uint32_t Parent = 0;
77   uint32_t End = 0;
78   uint32_t Next = 0;
79   uint32_t Offset = 0;
80   uint16_t Segment = 0;
81   uint16_t Length = 0;
82   ThunkOrdinal Thunk = ThunkOrdinal::Standard;
83   StringRef Name;
84   ArrayRef<uint8_t> VariantData;
85 
86   uint32_t RecordOffset = 0;
87 };
88 
89 // S_TRAMPOLINE
90 class TrampolineSym : public SymbolRecord {
91 public:
TrampolineSym(SymbolRecordKind Kind)92   explicit TrampolineSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
TrampolineSym(SymbolRecordKind Kind,uint32_t RecordOffset)93   TrampolineSym(SymbolRecordKind Kind, uint32_t RecordOffset)
94       : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
95 
96   TrampolineType Type;
97   uint16_t Size = 0;
98   uint32_t ThunkOffset = 0;
99   uint32_t TargetOffset = 0;
100   uint16_t ThunkSection = 0;
101   uint16_t TargetSection = 0;
102 
103   uint32_t RecordOffset = 0;
104 };
105 
106 // S_SECTION
107 class SectionSym : public SymbolRecord {
108 public:
SectionSym(SymbolRecordKind Kind)109   explicit SectionSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
SectionSym(SymbolRecordKind Kind,uint32_t RecordOffset)110   SectionSym(SymbolRecordKind Kind, uint32_t RecordOffset)
111       : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
112 
113   uint16_t SectionNumber = 0;
114   uint8_t Alignment = 0;
115   uint32_t Rva = 0;
116   uint32_t Length = 0;
117   uint32_t Characteristics = 0;
118   StringRef Name;
119 
120   uint32_t RecordOffset = 0;
121 };
122 
123 // S_COFFGROUP
124 class CoffGroupSym : public SymbolRecord {
125 public:
CoffGroupSym(SymbolRecordKind Kind)126   explicit CoffGroupSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
CoffGroupSym(SymbolRecordKind Kind,uint32_t RecordOffset)127   CoffGroupSym(SymbolRecordKind Kind, uint32_t RecordOffset)
128       : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
129 
130   uint32_t Size = 0;
131   uint32_t Characteristics = 0;
132   uint32_t Offset = 0;
133   uint16_t Segment = 0;
134   StringRef Name;
135 
136   uint32_t RecordOffset = 0;
137 };
138 
139 class ScopeEndSym : public SymbolRecord {
140 public:
ScopeEndSym(SymbolRecordKind Kind)141   explicit ScopeEndSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
ScopeEndSym(SymbolRecordKind Kind,uint32_t RecordOffset)142   ScopeEndSym(SymbolRecordKind Kind, uint32_t RecordOffset)
143       : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
144 
145   uint32_t RecordOffset = 0;
146 };
147 
148 class CallerSym : public SymbolRecord {
149 public:
CallerSym(SymbolRecordKind Kind)150   explicit CallerSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
CallerSym(SymbolRecordKind Kind,uint32_t RecordOffset)151   CallerSym(SymbolRecordKind Kind, uint32_t RecordOffset)
152       : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
153 
154   std::vector<TypeIndex> Indices;
155 
156   uint32_t RecordOffset = 0;
157 };
158 
159 struct DecodedAnnotation {
160   StringRef Name;
161   ArrayRef<uint8_t> Bytes;
162   BinaryAnnotationsOpCode OpCode = BinaryAnnotationsOpCode::Invalid;
163   uint32_t U1 = 0;
164   uint32_t U2 = 0;
165   int32_t S1 = 0;
166 };
167 
168 struct BinaryAnnotationIterator
169     : public iterator_facade_base<BinaryAnnotationIterator,
170                                   std::forward_iterator_tag,
171                                   DecodedAnnotation> {
172   BinaryAnnotationIterator() = default;
BinaryAnnotationIteratorBinaryAnnotationIterator173   BinaryAnnotationIterator(ArrayRef<uint8_t> Annotations) : Data(Annotations) {}
BinaryAnnotationIteratorBinaryAnnotationIterator174   BinaryAnnotationIterator(const BinaryAnnotationIterator &Other)
175       : Data(Other.Data) {}
176 
177   bool operator==(BinaryAnnotationIterator Other) const {
178     return Data == Other.Data;
179   }
180 
181   BinaryAnnotationIterator &operator=(const BinaryAnnotationIterator Other) {
182     Data = Other.Data;
183     return *this;
184   }
185 
186   BinaryAnnotationIterator &operator++() {
187     if (!ParseCurrentAnnotation()) {
188       *this = BinaryAnnotationIterator();
189       return *this;
190     }
191     Data = Next;
192     Next = ArrayRef<uint8_t>();
193     Current.reset();
194     return *this;
195   }
196 
197   const DecodedAnnotation &operator*() {
198     ParseCurrentAnnotation();
199     return Current.getValue();
200   }
201 
202 private:
GetCompressedAnnotationBinaryAnnotationIterator203   static uint32_t GetCompressedAnnotation(ArrayRef<uint8_t> &Annotations) {
204     if (Annotations.empty())
205       return -1;
206 
207     uint8_t FirstByte = Annotations.front();
208     Annotations = Annotations.drop_front();
209 
210     if ((FirstByte & 0x80) == 0x00)
211       return FirstByte;
212 
213     if (Annotations.empty())
214       return -1;
215 
216     uint8_t SecondByte = Annotations.front();
217     Annotations = Annotations.drop_front();
218 
219     if ((FirstByte & 0xC0) == 0x80)
220       return ((FirstByte & 0x3F) << 8) | SecondByte;
221 
222     if (Annotations.empty())
223       return -1;
224 
225     uint8_t ThirdByte = Annotations.front();
226     Annotations = Annotations.drop_front();
227 
228     if (Annotations.empty())
229       return -1;
230 
231     uint8_t FourthByte = Annotations.front();
232     Annotations = Annotations.drop_front();
233 
234     if ((FirstByte & 0xE0) == 0xC0)
235       return ((FirstByte & 0x1F) << 24) | (SecondByte << 16) |
236              (ThirdByte << 8) | FourthByte;
237 
238     return -1;
239   }
240 
DecodeSignedOperandBinaryAnnotationIterator241   static int32_t DecodeSignedOperand(uint32_t Operand) {
242     if (Operand & 1)
243       return -(Operand >> 1);
244     return Operand >> 1;
245   }
246 
DecodeSignedOperandBinaryAnnotationIterator247   static int32_t DecodeSignedOperand(ArrayRef<uint8_t> &Annotations) {
248     return DecodeSignedOperand(GetCompressedAnnotation(Annotations));
249   }
250 
ParseCurrentAnnotationBinaryAnnotationIterator251   bool ParseCurrentAnnotation() {
252     if (Current.hasValue())
253       return true;
254 
255     Next = Data;
256     uint32_t Op = GetCompressedAnnotation(Next);
257     DecodedAnnotation Result;
258     Result.OpCode = static_cast<BinaryAnnotationsOpCode>(Op);
259     switch (Result.OpCode) {
260     case BinaryAnnotationsOpCode::Invalid:
261       Result.Name = "Invalid";
262       Next = ArrayRef<uint8_t>();
263       break;
264     case BinaryAnnotationsOpCode::CodeOffset:
265       Result.Name = "CodeOffset";
266       Result.U1 = GetCompressedAnnotation(Next);
267       break;
268     case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
269       Result.Name = "ChangeCodeOffsetBase";
270       Result.U1 = GetCompressedAnnotation(Next);
271       break;
272     case BinaryAnnotationsOpCode::ChangeCodeOffset:
273       Result.Name = "ChangeCodeOffset";
274       Result.U1 = GetCompressedAnnotation(Next);
275       break;
276     case BinaryAnnotationsOpCode::ChangeCodeLength:
277       Result.Name = "ChangeCodeLength";
278       Result.U1 = GetCompressedAnnotation(Next);
279       break;
280     case BinaryAnnotationsOpCode::ChangeFile:
281       Result.Name = "ChangeFile";
282       Result.U1 = GetCompressedAnnotation(Next);
283       break;
284     case BinaryAnnotationsOpCode::ChangeLineEndDelta:
285       Result.Name = "ChangeLineEndDelta";
286       Result.U1 = GetCompressedAnnotation(Next);
287       break;
288     case BinaryAnnotationsOpCode::ChangeRangeKind:
289       Result.Name = "ChangeRangeKind";
290       Result.U1 = GetCompressedAnnotation(Next);
291       break;
292     case BinaryAnnotationsOpCode::ChangeColumnStart:
293       Result.Name = "ChangeColumnStart";
294       Result.U1 = GetCompressedAnnotation(Next);
295       break;
296     case BinaryAnnotationsOpCode::ChangeColumnEnd:
297       Result.Name = "ChangeColumnEnd";
298       Result.U1 = GetCompressedAnnotation(Next);
299       break;
300     case BinaryAnnotationsOpCode::ChangeLineOffset:
301       Result.Name = "ChangeLineOffset";
302       Result.S1 = DecodeSignedOperand(Next);
303       break;
304     case BinaryAnnotationsOpCode::ChangeColumnEndDelta:
305       Result.Name = "ChangeColumnEndDelta";
306       Result.S1 = DecodeSignedOperand(Next);
307       break;
308     case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: {
309       Result.Name = "ChangeCodeOffsetAndLineOffset";
310       uint32_t Annotation = GetCompressedAnnotation(Next);
311       Result.S1 = DecodeSignedOperand(Annotation >> 4);
312       Result.U1 = Annotation & 0xf;
313       break;
314     }
315     case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: {
316       Result.Name = "ChangeCodeLengthAndCodeOffset";
317       Result.U1 = GetCompressedAnnotation(Next);
318       Result.U2 = GetCompressedAnnotation(Next);
319       break;
320     }
321     }
322     Result.Bytes = Data.take_front(Data.size() - Next.size());
323     Current = Result;
324     return true;
325   }
326 
327   Optional<DecodedAnnotation> Current;
328   ArrayRef<uint8_t> Data;
329   ArrayRef<uint8_t> Next;
330 };
331 
332 // S_INLINESITE
333 class InlineSiteSym : public SymbolRecord {
334 public:
InlineSiteSym(SymbolRecordKind Kind)335   explicit InlineSiteSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
InlineSiteSym(uint32_t RecordOffset)336   explicit InlineSiteSym(uint32_t RecordOffset)
337       : SymbolRecord(SymbolRecordKind::InlineSiteSym),
338         RecordOffset(RecordOffset) {}
339 
annotations()340   iterator_range<BinaryAnnotationIterator> annotations() const {
341     return make_range(BinaryAnnotationIterator(AnnotationData),
342                       BinaryAnnotationIterator());
343   }
344 
345   uint32_t Parent = 0;
346   uint32_t End = 0;
347   TypeIndex Inlinee;
348   std::vector<uint8_t> AnnotationData;
349 
350   uint32_t RecordOffset = 0;
351 };
352 
353 struct PublicSym32Header {
354   ulittle32_t Flags;
355   ulittle32_t Offset;
356   ulittle16_t Segment;
357   // char Name[];
358 };
359 
360 // S_PUB32
361 class PublicSym32 : public SymbolRecord {
362 public:
PublicSym32()363   PublicSym32() : SymbolRecord(SymbolRecordKind::PublicSym32) {}
PublicSym32(SymbolRecordKind Kind)364   explicit PublicSym32(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
PublicSym32(uint32_t RecordOffset)365   explicit PublicSym32(uint32_t RecordOffset)
366       : SymbolRecord(SymbolRecordKind::PublicSym32),
367         RecordOffset(RecordOffset) {}
368 
369   PublicSymFlags Flags = PublicSymFlags::None;
370   uint32_t Offset = 0;
371   uint16_t Segment = 0;
372   StringRef Name;
373 
374   uint32_t RecordOffset = 0;
375 };
376 
377 // S_REGISTER
378 class RegisterSym : public SymbolRecord {
379 public:
RegisterSym(SymbolRecordKind Kind)380   explicit RegisterSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
RegisterSym(uint32_t RecordOffset)381   explicit RegisterSym(uint32_t RecordOffset)
382       : SymbolRecord(SymbolRecordKind::RegisterSym),
383         RecordOffset(RecordOffset) {}
384 
385   TypeIndex Index;
386   RegisterId Register;
387   StringRef Name;
388 
389   uint32_t RecordOffset = 0;
390 };
391 
392 // S_PROCREF, S_LPROCREF
393 class ProcRefSym : public SymbolRecord {
394 public:
ProcRefSym(SymbolRecordKind Kind)395   explicit ProcRefSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
ProcRefSym(uint32_t RecordOffset)396   explicit ProcRefSym(uint32_t RecordOffset)
397       : SymbolRecord(SymbolRecordKind::ProcRefSym), RecordOffset(RecordOffset) {
398   }
399 
400   uint32_t SumName = 0;
401   uint32_t SymOffset = 0;
402   uint16_t Module = 0;
403   StringRef Name;
404 
modi()405   uint16_t modi() const { return Module - 1; }
406   uint32_t RecordOffset = 0;
407 };
408 
409 // S_LOCAL
410 class LocalSym : public SymbolRecord {
411 public:
LocalSym(SymbolRecordKind Kind)412   explicit LocalSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
LocalSym(uint32_t RecordOffset)413   explicit LocalSym(uint32_t RecordOffset)
414       : SymbolRecord(SymbolRecordKind::LocalSym), RecordOffset(RecordOffset) {}
415 
416   TypeIndex Type;
417   LocalSymFlags Flags = LocalSymFlags::None;
418   StringRef Name;
419 
420   uint32_t RecordOffset = 0;
421 };
422 
423 struct LocalVariableAddrRange {
424   uint32_t OffsetStart = 0;
425   uint16_t ISectStart = 0;
426   uint16_t Range = 0;
427 };
428 
429 struct LocalVariableAddrGap {
430   uint16_t GapStartOffset = 0;
431   uint16_t Range = 0;
432 };
433 
434 enum : uint16_t { MaxDefRange = 0xf000 };
435 
436 // S_DEFRANGE
437 class DefRangeSym : public SymbolRecord {
438   static constexpr uint32_t RelocationOffset = 8;
439 
440 public:
DefRangeSym(SymbolRecordKind Kind)441   explicit DefRangeSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
DefRangeSym(uint32_t RecordOffset)442   explicit DefRangeSym(uint32_t RecordOffset)
443       : SymbolRecord(SymbolRecordKind::DefRangeSym),
444         RecordOffset(RecordOffset) {}
445 
getRelocationOffset()446   uint32_t getRelocationOffset() const {
447     return RecordOffset + RelocationOffset;
448   }
449 
450   uint32_t Program = 0;
451   LocalVariableAddrRange Range;
452   std::vector<LocalVariableAddrGap> Gaps;
453 
454   uint32_t RecordOffset = 0;
455 };
456 
457 // S_DEFRANGE_SUBFIELD
458 class DefRangeSubfieldSym : public SymbolRecord {
459   static constexpr uint32_t RelocationOffset = 12;
460 
461 public:
DefRangeSubfieldSym(SymbolRecordKind Kind)462   explicit DefRangeSubfieldSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
DefRangeSubfieldSym(uint32_t RecordOffset)463   explicit DefRangeSubfieldSym(uint32_t RecordOffset)
464       : SymbolRecord(SymbolRecordKind::DefRangeSubfieldSym),
465         RecordOffset(RecordOffset) {}
466 
getRelocationOffset()467   uint32_t getRelocationOffset() const {
468     return RecordOffset + RelocationOffset;
469   }
470 
471   uint32_t Program = 0;
472   uint16_t OffsetInParent = 0;
473   LocalVariableAddrRange Range;
474   std::vector<LocalVariableAddrGap> Gaps;
475 
476   uint32_t RecordOffset = 0;
477 };
478 
479 struct DefRangeRegisterHeader {
480   ulittle16_t Register;
481   ulittle16_t MayHaveNoName;
482 };
483 
484 // S_DEFRANGE_REGISTER
485 class DefRangeRegisterSym : public SymbolRecord {
486 public:
DefRangeRegisterSym(SymbolRecordKind Kind)487   explicit DefRangeRegisterSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
DefRangeRegisterSym(uint32_t RecordOffset)488   explicit DefRangeRegisterSym(uint32_t RecordOffset)
489       : SymbolRecord(SymbolRecordKind::DefRangeRegisterSym),
490         RecordOffset(RecordOffset) {}
491 
getRelocationOffset()492   uint32_t getRelocationOffset() const { return RecordOffset + sizeof(DefRangeRegisterHeader); }
493 
494   DefRangeRegisterHeader Hdr;
495   LocalVariableAddrRange Range;
496   std::vector<LocalVariableAddrGap> Gaps;
497 
498   uint32_t RecordOffset = 0;
499 };
500 
501 struct DefRangeSubfieldRegisterHeader {
502   ulittle16_t Register;
503   ulittle16_t MayHaveNoName;
504   ulittle32_t OffsetInParent;
505 };
506 
507 // S_DEFRANGE_SUBFIELD_REGISTER
508 class DefRangeSubfieldRegisterSym : public SymbolRecord {
509 public:
DefRangeSubfieldRegisterSym(SymbolRecordKind Kind)510   explicit DefRangeSubfieldRegisterSym(SymbolRecordKind Kind)
511       : SymbolRecord(Kind) {}
DefRangeSubfieldRegisterSym(uint32_t RecordOffset)512   explicit DefRangeSubfieldRegisterSym(uint32_t RecordOffset)
513       : SymbolRecord(SymbolRecordKind::DefRangeSubfieldRegisterSym),
514         RecordOffset(RecordOffset) {}
515 
getRelocationOffset()516   uint32_t getRelocationOffset() const { return RecordOffset + sizeof(DefRangeSubfieldRegisterHeader); }
517 
518   DefRangeSubfieldRegisterHeader Hdr;
519   LocalVariableAddrRange Range;
520   std::vector<LocalVariableAddrGap> Gaps;
521 
522   uint32_t RecordOffset = 0;
523 };
524 
525 struct DefRangeFramePointerRelHeader {
526   little32_t Offset;
527 };
528 
529 // S_DEFRANGE_FRAMEPOINTER_REL
530 class DefRangeFramePointerRelSym : public SymbolRecord {
531   static constexpr uint32_t RelocationOffset = 8;
532 
533 public:
DefRangeFramePointerRelSym(SymbolRecordKind Kind)534   explicit DefRangeFramePointerRelSym(SymbolRecordKind Kind)
535       : SymbolRecord(Kind) {}
DefRangeFramePointerRelSym(uint32_t RecordOffset)536   explicit DefRangeFramePointerRelSym(uint32_t RecordOffset)
537       : SymbolRecord(SymbolRecordKind::DefRangeFramePointerRelSym),
538         RecordOffset(RecordOffset) {}
539 
getRelocationOffset()540   uint32_t getRelocationOffset() const {
541     return RecordOffset + RelocationOffset;
542   }
543 
544   DefRangeFramePointerRelHeader Hdr;
545   LocalVariableAddrRange Range;
546   std::vector<LocalVariableAddrGap> Gaps;
547 
548   uint32_t RecordOffset = 0;
549 };
550 
551 struct DefRangeRegisterRelHeader {
552   ulittle16_t Register;
553   ulittle16_t Flags;
554   little32_t BasePointerOffset;
555 };
556 
557 // S_DEFRANGE_REGISTER_REL
558 class DefRangeRegisterRelSym : public SymbolRecord {
559 public:
DefRangeRegisterRelSym(SymbolRecordKind Kind)560   explicit DefRangeRegisterRelSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
DefRangeRegisterRelSym(uint32_t RecordOffset)561   explicit DefRangeRegisterRelSym(uint32_t RecordOffset)
562       : SymbolRecord(SymbolRecordKind::DefRangeRegisterRelSym),
563         RecordOffset(RecordOffset) {}
564 
565   // The flags implement this notional bitfield:
566   //   uint16_t IsSubfield : 1;
567   //   uint16_t Padding : 3;
568   //   uint16_t OffsetInParent : 12;
569   enum : uint16_t {
570     IsSubfieldFlag = 1,
571     OffsetInParentShift = 4,
572   };
573 
hasSpilledUDTMember()574   bool hasSpilledUDTMember() const { return Hdr.Flags & IsSubfieldFlag; }
offsetInParent()575   uint16_t offsetInParent() const { return Hdr.Flags >> OffsetInParentShift; }
576 
getRelocationOffset()577   uint32_t getRelocationOffset() const { return RecordOffset + sizeof(DefRangeRegisterRelHeader); }
578 
579   DefRangeRegisterRelHeader Hdr;
580   LocalVariableAddrRange Range;
581   std::vector<LocalVariableAddrGap> Gaps;
582 
583   uint32_t RecordOffset = 0;
584 };
585 
586 // S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE
587 class DefRangeFramePointerRelFullScopeSym : public SymbolRecord {
588 public:
DefRangeFramePointerRelFullScopeSym(SymbolRecordKind Kind)589   explicit DefRangeFramePointerRelFullScopeSym(SymbolRecordKind Kind)
590       : SymbolRecord(Kind) {}
DefRangeFramePointerRelFullScopeSym(uint32_t RecordOffset)591   explicit DefRangeFramePointerRelFullScopeSym(uint32_t RecordOffset)
592       : SymbolRecord(SymbolRecordKind::DefRangeFramePointerRelFullScopeSym),
593         RecordOffset(RecordOffset) {}
594 
595   int32_t Offset = 0;
596 
597   uint32_t RecordOffset = 0;
598 };
599 
600 // S_BLOCK32
601 class BlockSym : public SymbolRecord {
602   static constexpr uint32_t RelocationOffset = 16;
603 
604 public:
BlockSym(SymbolRecordKind Kind)605   explicit BlockSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
BlockSym(uint32_t RecordOffset)606   explicit BlockSym(uint32_t RecordOffset)
607       : SymbolRecord(SymbolRecordKind::BlockSym), RecordOffset(RecordOffset) {}
608 
getRelocationOffset()609   uint32_t getRelocationOffset() const {
610     return RecordOffset + RelocationOffset;
611   }
612 
613   uint32_t Parent = 0;
614   uint32_t End = 0;
615   uint32_t CodeSize = 0;
616   uint32_t CodeOffset = 0;
617   uint16_t Segment = 0;
618   StringRef Name;
619 
620   uint32_t RecordOffset = 0;
621 };
622 
623 // S_LABEL32
624 class LabelSym : public SymbolRecord {
625   static constexpr uint32_t RelocationOffset = 4;
626 
627 public:
LabelSym(SymbolRecordKind Kind)628   explicit LabelSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
LabelSym(uint32_t RecordOffset)629   explicit LabelSym(uint32_t RecordOffset)
630       : SymbolRecord(SymbolRecordKind::LabelSym), RecordOffset(RecordOffset) {}
631 
getRelocationOffset()632   uint32_t getRelocationOffset() const {
633     return RecordOffset + RelocationOffset;
634   }
635 
636   uint32_t CodeOffset = 0;
637   uint16_t Segment = 0;
638   ProcSymFlags Flags = ProcSymFlags::None;
639   StringRef Name;
640 
641   uint32_t RecordOffset = 0;
642 };
643 
644 // S_OBJNAME
645 class ObjNameSym : public SymbolRecord {
646 public:
ObjNameSym()647   explicit ObjNameSym() : SymbolRecord(SymbolRecordKind::ObjNameSym) {}
ObjNameSym(SymbolRecordKind Kind)648   explicit ObjNameSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
ObjNameSym(uint32_t RecordOffset)649   explicit ObjNameSym(uint32_t RecordOffset)
650       : SymbolRecord(SymbolRecordKind::ObjNameSym), RecordOffset(RecordOffset) {
651   }
652 
653   uint32_t Signature = 0;
654   StringRef Name;
655 
656   uint32_t RecordOffset = 0;
657 };
658 
659 // S_ENVBLOCK
660 class EnvBlockSym : public SymbolRecord {
661 public:
EnvBlockSym(SymbolRecordKind Kind)662   explicit EnvBlockSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
EnvBlockSym(uint32_t RecordOffset)663   explicit EnvBlockSym(uint32_t RecordOffset)
664       : SymbolRecord(SymbolRecordKind::EnvBlockSym),
665         RecordOffset(RecordOffset) {}
666 
667   std::vector<StringRef> Fields;
668 
669   uint32_t RecordOffset = 0;
670 };
671 
672 // S_EXPORT
673 class ExportSym : public SymbolRecord {
674 public:
ExportSym(SymbolRecordKind Kind)675   explicit ExportSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
ExportSym(uint32_t RecordOffset)676   explicit ExportSym(uint32_t RecordOffset)
677       : SymbolRecord(SymbolRecordKind::ExportSym), RecordOffset(RecordOffset) {}
678 
679   uint16_t Ordinal = 0;
680   ExportFlags Flags = ExportFlags::None;
681   StringRef Name;
682 
683   uint32_t RecordOffset = 0;
684 };
685 
686 // S_FILESTATIC
687 class FileStaticSym : public SymbolRecord {
688 public:
FileStaticSym(SymbolRecordKind Kind)689   explicit FileStaticSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
FileStaticSym(uint32_t RecordOffset)690   explicit FileStaticSym(uint32_t RecordOffset)
691       : SymbolRecord(SymbolRecordKind::FileStaticSym),
692         RecordOffset(RecordOffset) {}
693 
694   TypeIndex Index;
695   uint32_t ModFilenameOffset = 0;
696   LocalSymFlags Flags = LocalSymFlags::None;
697   StringRef Name;
698 
699   uint32_t RecordOffset = 0;
700 };
701 
702 // S_COMPILE2
703 class Compile2Sym : public SymbolRecord {
704 public:
Compile2Sym(SymbolRecordKind Kind)705   explicit Compile2Sym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
Compile2Sym(uint32_t RecordOffset)706   explicit Compile2Sym(uint32_t RecordOffset)
707       : SymbolRecord(SymbolRecordKind::Compile2Sym),
708         RecordOffset(RecordOffset) {}
709 
710   CompileSym2Flags Flags = CompileSym2Flags::None;
711   CPUType Machine;
712   uint16_t VersionFrontendMajor = 0;
713   uint16_t VersionFrontendMinor = 0;
714   uint16_t VersionFrontendBuild = 0;
715   uint16_t VersionBackendMajor = 0;
716   uint16_t VersionBackendMinor = 0;
717   uint16_t VersionBackendBuild = 0;
718   StringRef Version;
719   std::vector<StringRef> ExtraStrings;
720 
getLanguage()721   uint8_t getLanguage() const { return static_cast<uint32_t>(Flags) & 0xFF; }
getFlags()722   uint32_t getFlags() const { return static_cast<uint32_t>(Flags) & ~0xFF; }
723 
724   uint32_t RecordOffset = 0;
725 };
726 
727 // S_COMPILE3
728 class Compile3Sym : public SymbolRecord {
729 public:
Compile3Sym()730   Compile3Sym() : SymbolRecord(SymbolRecordKind::Compile3Sym) {}
Compile3Sym(SymbolRecordKind Kind)731   explicit Compile3Sym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
Compile3Sym(uint32_t RecordOffset)732   explicit Compile3Sym(uint32_t RecordOffset)
733       : SymbolRecord(SymbolRecordKind::Compile3Sym),
734         RecordOffset(RecordOffset) {}
735 
736   CompileSym3Flags Flags = CompileSym3Flags::None;
737   CPUType Machine;
738   uint16_t VersionFrontendMajor = 0;
739   uint16_t VersionFrontendMinor = 0;
740   uint16_t VersionFrontendBuild = 0;
741   uint16_t VersionFrontendQFE = 0;
742   uint16_t VersionBackendMajor = 0;
743   uint16_t VersionBackendMinor = 0;
744   uint16_t VersionBackendBuild = 0;
745   uint16_t VersionBackendQFE = 0;
746   StringRef Version;
747 
setLanguage(SourceLanguage Lang)748   void setLanguage(SourceLanguage Lang) {
749     Flags = CompileSym3Flags((uint32_t(Flags) & 0xFFFFFF00) | uint32_t(Lang));
750   }
751 
getLanguage()752   SourceLanguage getLanguage() const {
753     return static_cast<SourceLanguage>(static_cast<uint32_t>(Flags) & 0xFF);
754   }
getFlags()755   CompileSym3Flags getFlags() const {
756     return static_cast<CompileSym3Flags>(static_cast<uint32_t>(Flags) & ~0xFF);
757   }
758 
hasOptimizations()759   bool hasOptimizations() const {
760     return CompileSym3Flags::None !=
761            (getFlags() & (CompileSym3Flags::PGO | CompileSym3Flags::LTCG));
762   }
763 
764   uint32_t RecordOffset = 0;
765 };
766 
767 // S_FRAMEPROC
768 class FrameProcSym : public SymbolRecord {
769 public:
FrameProcSym(SymbolRecordKind Kind)770   explicit FrameProcSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
FrameProcSym(uint32_t RecordOffset)771   explicit FrameProcSym(uint32_t RecordOffset)
772       : SymbolRecord(SymbolRecordKind::FrameProcSym),
773         RecordOffset(RecordOffset) {}
774 
775   uint32_t TotalFrameBytes = 0;
776   uint32_t PaddingFrameBytes = 0;
777   uint32_t OffsetToPadding = 0;
778   uint32_t BytesOfCalleeSavedRegisters = 0;
779   uint32_t OffsetOfExceptionHandler = 0;
780   uint16_t SectionIdOfExceptionHandler = 0;
781   FrameProcedureOptions Flags = FrameProcedureOptions::None;
782 
783   /// Extract the register this frame uses to refer to local variables.
getLocalFramePtrReg(CPUType CPU)784   RegisterId getLocalFramePtrReg(CPUType CPU) const {
785     return decodeFramePtrReg(
786         EncodedFramePtrReg((uint32_t(Flags) >> 14U) & 0x3U), CPU);
787   }
788 
789   /// Extract the register this frame uses to refer to parameters.
getParamFramePtrReg(CPUType CPU)790   RegisterId getParamFramePtrReg(CPUType CPU) const {
791     return decodeFramePtrReg(
792         EncodedFramePtrReg((uint32_t(Flags) >> 16U) & 0x3U), CPU);
793   }
794 
795   uint32_t RecordOffset = 0;
796 
797 private:
798 };
799 
800 // S_CALLSITEINFO
801 class CallSiteInfoSym : public SymbolRecord {
802   static constexpr uint32_t RelocationOffset = 4;
803 
804 public:
CallSiteInfoSym(SymbolRecordKind Kind)805   explicit CallSiteInfoSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
CallSiteInfoSym(uint32_t RecordOffset)806   explicit CallSiteInfoSym(uint32_t RecordOffset)
807       : SymbolRecord(SymbolRecordKind::CallSiteInfoSym) {}
808 
getRelocationOffset()809   uint32_t getRelocationOffset() const {
810     return RecordOffset + RelocationOffset;
811   }
812 
813   uint32_t CodeOffset = 0;
814   uint16_t Segment = 0;
815   TypeIndex Type;
816 
817   uint32_t RecordOffset = 0;
818 };
819 
820 // S_HEAPALLOCSITE
821 class HeapAllocationSiteSym : public SymbolRecord {
822   static constexpr uint32_t RelocationOffset = 4;
823 
824 public:
HeapAllocationSiteSym(SymbolRecordKind Kind)825   explicit HeapAllocationSiteSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
HeapAllocationSiteSym(uint32_t RecordOffset)826   explicit HeapAllocationSiteSym(uint32_t RecordOffset)
827       : SymbolRecord(SymbolRecordKind::HeapAllocationSiteSym),
828         RecordOffset(RecordOffset) {}
829 
getRelocationOffset()830   uint32_t getRelocationOffset() const {
831     return RecordOffset + RelocationOffset;
832   }
833 
834   uint32_t CodeOffset = 0;
835   uint16_t Segment = 0;
836   uint16_t CallInstructionSize = 0;
837   TypeIndex Type;
838 
839   uint32_t RecordOffset = 0;
840 };
841 
842 // S_FRAMECOOKIE
843 class FrameCookieSym : public SymbolRecord {
844   static constexpr uint32_t RelocationOffset = 4;
845 
846 public:
FrameCookieSym(SymbolRecordKind Kind)847   explicit FrameCookieSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
FrameCookieSym(uint32_t RecordOffset)848   explicit FrameCookieSym(uint32_t RecordOffset)
849       : SymbolRecord(SymbolRecordKind::FrameCookieSym) {}
850 
getRelocationOffset()851   uint32_t getRelocationOffset() const {
852     return RecordOffset + RelocationOffset;
853   }
854 
855   uint32_t CodeOffset = 0;
856   uint16_t Register = 0;
857   FrameCookieKind CookieKind;
858   uint8_t Flags = 0;
859 
860   uint32_t RecordOffset = 0;
861 };
862 
863 // S_UDT, S_COBOLUDT
864 class UDTSym : public SymbolRecord {
865 public:
UDTSym(SymbolRecordKind Kind)866   explicit UDTSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
UDTSym(uint32_t RecordOffset)867   explicit UDTSym(uint32_t RecordOffset)
868       : SymbolRecord(SymbolRecordKind::UDTSym) {}
869 
870   TypeIndex Type;
871   StringRef Name;
872 
873   uint32_t RecordOffset = 0;
874 };
875 
876 // S_BUILDINFO
877 class BuildInfoSym : public SymbolRecord {
878 public:
BuildInfoSym(SymbolRecordKind Kind)879   explicit BuildInfoSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
BuildInfoSym(uint32_t RecordOffset)880   explicit BuildInfoSym(uint32_t RecordOffset)
881       : SymbolRecord(SymbolRecordKind::BuildInfoSym),
882         RecordOffset(RecordOffset) {}
883 
884   TypeIndex BuildId;
885 
886   uint32_t RecordOffset = 0;
887 };
888 
889 // S_BPREL32
890 class BPRelativeSym : public SymbolRecord {
891 public:
BPRelativeSym(SymbolRecordKind Kind)892   explicit BPRelativeSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
BPRelativeSym(uint32_t RecordOffset)893   explicit BPRelativeSym(uint32_t RecordOffset)
894       : SymbolRecord(SymbolRecordKind::BPRelativeSym),
895         RecordOffset(RecordOffset) {}
896 
897   int32_t Offset = 0;
898   TypeIndex Type;
899   StringRef Name;
900 
901   uint32_t RecordOffset = 0;
902 };
903 
904 // S_REGREL32
905 class RegRelativeSym : public SymbolRecord {
906 public:
RegRelativeSym(SymbolRecordKind Kind)907   explicit RegRelativeSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
RegRelativeSym(uint32_t RecordOffset)908   explicit RegRelativeSym(uint32_t RecordOffset)
909       : SymbolRecord(SymbolRecordKind::RegRelativeSym),
910         RecordOffset(RecordOffset) {}
911 
912   uint32_t Offset = 0;
913   TypeIndex Type;
914   RegisterId Register;
915   StringRef Name;
916 
917   uint32_t RecordOffset = 0;
918 };
919 
920 // S_CONSTANT, S_MANCONSTANT
921 class ConstantSym : public SymbolRecord {
922 public:
ConstantSym(SymbolRecordKind Kind)923   explicit ConstantSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
ConstantSym(uint32_t RecordOffset)924   explicit ConstantSym(uint32_t RecordOffset)
925       : SymbolRecord(SymbolRecordKind::ConstantSym),
926         RecordOffset(RecordOffset) {}
927 
928   TypeIndex Type;
929   APSInt Value;
930   StringRef Name;
931 
932   uint32_t RecordOffset = 0;
933 };
934 
935 // S_LDATA32, S_GDATA32, S_LMANDATA, S_GMANDATA
936 class DataSym : public SymbolRecord {
937   static constexpr uint32_t RelocationOffset = 8;
938 
939 public:
DataSym(SymbolRecordKind Kind)940   explicit DataSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
DataSym(uint32_t RecordOffset)941   explicit DataSym(uint32_t RecordOffset)
942       : SymbolRecord(SymbolRecordKind::DataSym), RecordOffset(RecordOffset) {}
943 
getRelocationOffset()944   uint32_t getRelocationOffset() const {
945     return RecordOffset + RelocationOffset;
946   }
947 
948   TypeIndex Type;
949   uint32_t DataOffset = 0;
950   uint16_t Segment = 0;
951   StringRef Name;
952 
953   uint32_t RecordOffset = 0;
954 };
955 
956 // S_LTHREAD32, S_GTHREAD32
957 class ThreadLocalDataSym : public SymbolRecord {
958   static constexpr uint32_t RelocationOffset = 8;
959 
960 public:
ThreadLocalDataSym(SymbolRecordKind Kind)961   explicit ThreadLocalDataSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
ThreadLocalDataSym(uint32_t RecordOffset)962   explicit ThreadLocalDataSym(uint32_t RecordOffset)
963       : SymbolRecord(SymbolRecordKind::ThreadLocalDataSym),
964         RecordOffset(RecordOffset) {}
965 
getRelocationOffset()966   uint32_t getRelocationOffset() const {
967     return RecordOffset + RelocationOffset;
968   }
969 
970   TypeIndex Type;
971   uint32_t DataOffset = 0;
972   uint16_t Segment = 0;
973   StringRef Name;
974 
975   uint32_t RecordOffset = 0;
976 };
977 
978 // S_UNAMESPACE
979 class UsingNamespaceSym : public SymbolRecord {
980 public:
UsingNamespaceSym(SymbolRecordKind Kind)981   explicit UsingNamespaceSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
UsingNamespaceSym(uint32_t RecordOffset)982   explicit UsingNamespaceSym(uint32_t RecordOffset)
983       : SymbolRecord(SymbolRecordKind::UsingNamespaceSym),
984         RecordOffset(RecordOffset) {}
985 
986   StringRef Name;
987 
988   uint32_t RecordOffset = 0;
989 };
990 
991 // S_ANNOTATION
992 class AnnotationSym : public SymbolRecord {
993 public:
AnnotationSym(SymbolRecordKind Kind)994   explicit AnnotationSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
AnnotationSym(uint32_t RecordOffset)995   explicit AnnotationSym(uint32_t RecordOffset)
996       : SymbolRecord(SymbolRecordKind::AnnotationSym),
997         RecordOffset(RecordOffset) {}
998 
999   uint32_t CodeOffset = 0;
1000   uint16_t Segment = 0;
1001   std::vector<StringRef> Strings;
1002 
1003   uint32_t RecordOffset = 0;
1004 };
1005 
1006 Expected<CVSymbol> readSymbolFromStream(BinaryStreamRef Stream,
1007                                         uint32_t Offset);
1008 
1009 } // end namespace codeview
1010 } // end namespace llvm
1011 
1012 #endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H
1013