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