//===- SymbolRecord.h -------------------------------------------*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H
 
#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H
 
 
 
#include "llvm/ADT/APSInt.h"
 
#include "llvm/ADT/ArrayRef.h"
 
#include "llvm/ADT/StringRef.h"
 
#include "llvm/ADT/iterator.h"
 
#include "llvm/ADT/iterator_range.h"
 
#include "llvm/DebugInfo/CodeView/CVRecord.h"
 
#include "llvm/DebugInfo/CodeView/CodeView.h"
 
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
 
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
 
#include "llvm/Support/BinaryStreamArray.h"
 
#include "llvm/Support/Endian.h"
 
#include <cstdint>
 
#include <vector>
 
 
 
namespace llvm {
 
namespace codeview {
 
 
 
class SymbolRecord {
 
protected:
 
  explicit SymbolRecord(SymbolRecordKind Kind) : Kind(Kind) {}
 
 
 
public:
 
  SymbolRecordKind getKind() const { return Kind; }
 
 
 
  SymbolRecordKind Kind;
 
};
 
 
 
// S_GPROC32, S_LPROC32, S_GPROC32_ID, S_LPROC32_ID, S_LPROC32_DPC or
 
// S_LPROC32_DPC_ID
 
class ProcSym : public SymbolRecord {
 
  static constexpr uint32_t RelocationOffset = 32;
 
 
 
public:
 
  explicit ProcSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  ProcSym(SymbolRecordKind Kind, uint32_t RecordOffset)
 
      : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
 
 
 
  uint32_t getRelocationOffset() const {
 
    return RecordOffset + RelocationOffset;
 
  }
 
 
 
  uint32_t Parent = 0;
 
  uint32_t End = 0;
 
  uint32_t Next = 0;
 
  uint32_t CodeSize = 0;
 
  uint32_t DbgStart = 0;
 
  uint32_t DbgEnd = 0;
 
  TypeIndex FunctionType;
 
  uint32_t CodeOffset = 0;
 
  uint16_t Segment = 0;
 
  ProcSymFlags Flags = ProcSymFlags::None;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_THUNK32
 
class Thunk32Sym : public SymbolRecord {
 
public:
 
  explicit Thunk32Sym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  Thunk32Sym(SymbolRecordKind Kind, uint32_t RecordOffset)
 
      : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
 
 
 
  uint32_t Parent = 0;
 
  uint32_t End = 0;
 
  uint32_t Next = 0;
 
  uint32_t Offset = 0;
 
  uint16_t Segment = 0;
 
  uint16_t Length = 0;
 
  ThunkOrdinal Thunk = ThunkOrdinal::Standard;
 
  StringRef Name;
 
  ArrayRef<uint8_t> VariantData;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_TRAMPOLINE
 
class TrampolineSym : public SymbolRecord {
 
public:
 
  explicit TrampolineSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  TrampolineSym(SymbolRecordKind Kind, uint32_t RecordOffset)
 
      : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
 
 
 
  TrampolineType Type;
 
  uint16_t Size = 0;
 
  uint32_t ThunkOffset = 0;
 
  uint32_t TargetOffset = 0;
 
  uint16_t ThunkSection = 0;
 
  uint16_t TargetSection = 0;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_SECTION
 
class SectionSym : public SymbolRecord {
 
public:
 
  explicit SectionSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  SectionSym(SymbolRecordKind Kind, uint32_t RecordOffset)
 
      : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
 
 
 
  uint16_t SectionNumber = 0;
 
  uint8_t Alignment = 0;
 
  uint32_t Rva = 0;
 
  uint32_t Length = 0;
 
  uint32_t Characteristics = 0;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_COFFGROUP
 
class CoffGroupSym : public SymbolRecord {
 
public:
 
  explicit CoffGroupSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  CoffGroupSym(SymbolRecordKind Kind, uint32_t RecordOffset)
 
      : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
 
 
 
  uint32_t Size = 0;
 
  uint32_t Characteristics = 0;
 
  uint32_t Offset = 0;
 
  uint16_t Segment = 0;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
class ScopeEndSym : public SymbolRecord {
 
public:
 
  explicit ScopeEndSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  ScopeEndSym(SymbolRecordKind Kind, uint32_t RecordOffset)
 
      : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
class CallerSym : public SymbolRecord {
 
public:
 
  explicit CallerSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  CallerSym(SymbolRecordKind Kind, uint32_t RecordOffset)
 
      : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
 
 
 
  std::vector<TypeIndex> Indices;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
struct DecodedAnnotation {
 
  StringRef Name;
 
  ArrayRef<uint8_t> Bytes;
 
  BinaryAnnotationsOpCode OpCode = BinaryAnnotationsOpCode::Invalid;
 
  uint32_t U1 = 0;
 
  uint32_t U2 = 0;
 
  int32_t S1 = 0;
 
};
 
 
 
struct BinaryAnnotationIterator
 
    : public iterator_facade_base<BinaryAnnotationIterator,
 
                                  std::forward_iterator_tag,
 
                                  DecodedAnnotation> {
 
  BinaryAnnotationIterator() = default;
 
  BinaryAnnotationIterator(ArrayRef<uint8_t> Annotations) : Data(Annotations) {}
 
  BinaryAnnotationIterator(const BinaryAnnotationIterator &Other)
 
      : Data(Other.Data) {}
 
 
 
  bool operator==(BinaryAnnotationIterator Other) const {
 
    return Data == Other.Data;
 
  }
 
 
 
  BinaryAnnotationIterator &operator=(const BinaryAnnotationIterator Other) {
 
    Data = Other.Data;
 
    return *this;
 
  }
 
 
 
  BinaryAnnotationIterator &operator++() {
 
    if (!ParseCurrentAnnotation()) {
 
      *this = BinaryAnnotationIterator();
 
      return *this;
 
    }
 
    Data = Next;
 
    Next = ArrayRef<uint8_t>();
 
    Current.reset();
 
    return *this;
 
  }
 
 
 
  const DecodedAnnotation &operator*() {
 
    ParseCurrentAnnotation();
 
    return *Current;
 
  }
 
 
 
private:
 
  static uint32_t GetCompressedAnnotation(ArrayRef<uint8_t> &Annotations) {
 
    if (Annotations.empty())
 
      return -1;
 
 
 
    uint8_t FirstByte = Annotations.front();
 
    Annotations = Annotations.drop_front();
 
 
 
    if ((FirstByte & 0x80) == 0x00)
 
      return FirstByte;
 
 
 
    if (Annotations.empty())
 
      return -1;
 
 
 
    uint8_t SecondByte = Annotations.front();
 
    Annotations = Annotations.drop_front();
 
 
 
    if ((FirstByte & 0xC0) == 0x80)
 
      return ((FirstByte & 0x3F) << 8) | SecondByte;
 
 
 
    if (Annotations.empty())
 
      return -1;
 
 
 
    uint8_t ThirdByte = Annotations.front();
 
    Annotations = Annotations.drop_front();
 
 
 
    if (Annotations.empty())
 
      return -1;
 
 
 
    uint8_t FourthByte = Annotations.front();
 
    Annotations = Annotations.drop_front();
 
 
 
    if ((FirstByte & 0xE0) == 0xC0)
 
      return ((FirstByte & 0x1F) << 24) | (SecondByte << 16) |
 
             (ThirdByte << 8) | FourthByte;
 
 
 
    return -1;
 
  }
 
 
 
  static int32_t DecodeSignedOperand(uint32_t Operand) {
 
    if (Operand & 1)
 
      return -(Operand >> 1);
 
    return Operand >> 1;
 
  }
 
 
 
  static int32_t DecodeSignedOperand(ArrayRef<uint8_t> &Annotations) {
 
    return DecodeSignedOperand(GetCompressedAnnotation(Annotations));
 
  }
 
 
 
  bool ParseCurrentAnnotation() {
 
    if (Current)
 
      return true;
 
 
 
    Next = Data;
 
    uint32_t Op = GetCompressedAnnotation(Next);
 
    DecodedAnnotation Result;
 
    Result.OpCode = static_cast<BinaryAnnotationsOpCode>(Op);
 
    switch (Result.OpCode) {
 
    case BinaryAnnotationsOpCode::Invalid:
 
      Result.Name = "Invalid";
 
      Next = ArrayRef<uint8_t>();
 
      break;
 
    case BinaryAnnotationsOpCode::CodeOffset:
 
      Result.Name = "CodeOffset";
 
      Result.U1 = GetCompressedAnnotation(Next);
 
      break;
 
    case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
 
      Result.Name = "ChangeCodeOffsetBase";
 
      Result.U1 = GetCompressedAnnotation(Next);
 
      break;
 
    case BinaryAnnotationsOpCode::ChangeCodeOffset:
 
      Result.Name = "ChangeCodeOffset";
 
      Result.U1 = GetCompressedAnnotation(Next);
 
      break;
 
    case BinaryAnnotationsOpCode::ChangeCodeLength:
 
      Result.Name = "ChangeCodeLength";
 
      Result.U1 = GetCompressedAnnotation(Next);
 
      break;
 
    case BinaryAnnotationsOpCode::ChangeFile:
 
      Result.Name = "ChangeFile";
 
      Result.U1 = GetCompressedAnnotation(Next);
 
      break;
 
    case BinaryAnnotationsOpCode::ChangeLineEndDelta:
 
      Result.Name = "ChangeLineEndDelta";
 
      Result.U1 = GetCompressedAnnotation(Next);
 
      break;
 
    case BinaryAnnotationsOpCode::ChangeRangeKind:
 
      Result.Name = "ChangeRangeKind";
 
      Result.U1 = GetCompressedAnnotation(Next);
 
      break;
 
    case BinaryAnnotationsOpCode::ChangeColumnStart:
 
      Result.Name = "ChangeColumnStart";
 
      Result.U1 = GetCompressedAnnotation(Next);
 
      break;
 
    case BinaryAnnotationsOpCode::ChangeColumnEnd:
 
      Result.Name = "ChangeColumnEnd";
 
      Result.U1 = GetCompressedAnnotation(Next);
 
      break;
 
    case BinaryAnnotationsOpCode::ChangeLineOffset:
 
      Result.Name = "ChangeLineOffset";
 
      Result.S1 = DecodeSignedOperand(Next);
 
      break;
 
    case BinaryAnnotationsOpCode::ChangeColumnEndDelta:
 
      Result.Name = "ChangeColumnEndDelta";
 
      Result.S1 = DecodeSignedOperand(Next);
 
      break;
 
    case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: {
 
      Result.Name = "ChangeCodeOffsetAndLineOffset";
 
      uint32_t Annotation = GetCompressedAnnotation(Next);
 
      Result.S1 = DecodeSignedOperand(Annotation >> 4);
 
      Result.U1 = Annotation & 0xf;
 
      break;
 
    }
 
    case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: {
 
      Result.Name = "ChangeCodeLengthAndCodeOffset";
 
      Result.U1 = GetCompressedAnnotation(Next);
 
      Result.U2 = GetCompressedAnnotation(Next);
 
      break;
 
    }
 
    }
 
    Result.Bytes = Data.take_front(Data.size() - Next.size());
 
    Current = Result;
 
    return true;
 
  }
 
 
 
  std::optional<DecodedAnnotation> Current;
 
  ArrayRef<uint8_t> Data;
 
  ArrayRef<uint8_t> Next;
 
};
 
 
 
// S_INLINESITE
 
class InlineSiteSym : public SymbolRecord {
 
public:
 
  explicit InlineSiteSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit InlineSiteSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::InlineSiteSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  iterator_range<BinaryAnnotationIterator> annotations() const {
 
    return make_range(BinaryAnnotationIterator(AnnotationData),
 
                      BinaryAnnotationIterator());
 
  }
 
 
 
  uint32_t Parent = 0;
 
  uint32_t End = 0;
 
  TypeIndex Inlinee;
 
  std::vector<uint8_t> AnnotationData;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
struct PublicSym32Header {
 
  ulittle32_t Flags;
 
  ulittle32_t Offset;
 
  ulittle16_t Segment;
 
  // char Name[];
 
};
 
 
 
// S_PUB32
 
class PublicSym32 : public SymbolRecord {
 
public:
 
  PublicSym32() : SymbolRecord(SymbolRecordKind::PublicSym32) {}
 
  explicit PublicSym32(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit PublicSym32(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::PublicSym32),
 
        RecordOffset(RecordOffset) {}
 
 
 
  PublicSymFlags Flags = PublicSymFlags::None;
 
  uint32_t Offset = 0;
 
  uint16_t Segment = 0;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_REGISTER
 
class RegisterSym : public SymbolRecord {
 
public:
 
  explicit RegisterSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit RegisterSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::RegisterSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  TypeIndex Index;
 
  RegisterId Register;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_PROCREF, S_LPROCREF
 
class ProcRefSym : public SymbolRecord {
 
public:
 
  explicit ProcRefSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit ProcRefSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::ProcRefSym), RecordOffset(RecordOffset) {
 
  }
 
 
 
  uint32_t SumName = 0;
 
  uint32_t SymOffset = 0;
 
  uint16_t Module = 0;
 
  StringRef Name;
 
 
 
  uint16_t modi() const { return Module - 1; }
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_LOCAL
 
class LocalSym : public SymbolRecord {
 
public:
 
  explicit LocalSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit LocalSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::LocalSym), RecordOffset(RecordOffset) {}
 
 
 
  TypeIndex Type;
 
  LocalSymFlags Flags = LocalSymFlags::None;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
struct LocalVariableAddrRange {
 
  uint32_t OffsetStart = 0;
 
  uint16_t ISectStart = 0;
 
  uint16_t Range = 0;
 
};
 
 
 
struct LocalVariableAddrGap {
 
  uint16_t GapStartOffset = 0;
 
  uint16_t Range = 0;
 
};
 
 
 
enum : uint16_t { MaxDefRange = 0xf000 };
 
 
 
// S_DEFRANGE
 
class DefRangeSym : public SymbolRecord {
 
  static constexpr uint32_t RelocationOffset = 8;
 
 
 
public:
 
  explicit DefRangeSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit DefRangeSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::DefRangeSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  uint32_t getRelocationOffset() const {
 
    return RecordOffset + RelocationOffset;
 
  }
 
 
 
  uint32_t Program = 0;
 
  LocalVariableAddrRange Range;
 
  std::vector<LocalVariableAddrGap> Gaps;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_DEFRANGE_SUBFIELD
 
class DefRangeSubfieldSym : public SymbolRecord {
 
  static constexpr uint32_t RelocationOffset = 12;
 
 
 
public:
 
  explicit DefRangeSubfieldSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit DefRangeSubfieldSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::DefRangeSubfieldSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  uint32_t getRelocationOffset() const {
 
    return RecordOffset + RelocationOffset;
 
  }
 
 
 
  uint32_t Program = 0;
 
  uint16_t OffsetInParent = 0;
 
  LocalVariableAddrRange Range;
 
  std::vector<LocalVariableAddrGap> Gaps;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
struct DefRangeRegisterHeader {
 
  ulittle16_t Register;
 
  ulittle16_t MayHaveNoName;
 
};
 
 
 
// S_DEFRANGE_REGISTER
 
class DefRangeRegisterSym : public SymbolRecord {
 
public:
 
  explicit DefRangeRegisterSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit DefRangeRegisterSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::DefRangeRegisterSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  uint32_t getRelocationOffset() const { return RecordOffset + sizeof(DefRangeRegisterHeader); }
 
 
 
  DefRangeRegisterHeader Hdr;
 
  LocalVariableAddrRange Range;
 
  std::vector<LocalVariableAddrGap> Gaps;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
struct DefRangeSubfieldRegisterHeader {
 
  ulittle16_t Register;
 
  ulittle16_t MayHaveNoName;
 
  ulittle32_t OffsetInParent;
 
};
 
 
 
// S_DEFRANGE_SUBFIELD_REGISTER
 
class DefRangeSubfieldRegisterSym : public SymbolRecord {
 
public:
 
  explicit DefRangeSubfieldRegisterSym(SymbolRecordKind Kind)
 
      : SymbolRecord(Kind) {}
 
  explicit DefRangeSubfieldRegisterSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::DefRangeSubfieldRegisterSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  uint32_t getRelocationOffset() const { return RecordOffset + sizeof(DefRangeSubfieldRegisterHeader); }
 
 
 
  DefRangeSubfieldRegisterHeader Hdr;
 
  LocalVariableAddrRange Range;
 
  std::vector<LocalVariableAddrGap> Gaps;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
struct DefRangeFramePointerRelHeader {
 
  little32_t Offset;
 
};
 
 
 
// S_DEFRANGE_FRAMEPOINTER_REL
 
class DefRangeFramePointerRelSym : public SymbolRecord {
 
  static constexpr uint32_t RelocationOffset = 8;
 
 
 
public:
 
  explicit DefRangeFramePointerRelSym(SymbolRecordKind Kind)
 
      : SymbolRecord(Kind) {}
 
  explicit DefRangeFramePointerRelSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::DefRangeFramePointerRelSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  uint32_t getRelocationOffset() const {
 
    return RecordOffset + RelocationOffset;
 
  }
 
 
 
  DefRangeFramePointerRelHeader Hdr;
 
  LocalVariableAddrRange Range;
 
  std::vector<LocalVariableAddrGap> Gaps;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
struct DefRangeRegisterRelHeader {
 
  ulittle16_t Register;
 
  ulittle16_t Flags;
 
  little32_t BasePointerOffset;
 
};
 
 
 
// S_DEFRANGE_REGISTER_REL
 
class DefRangeRegisterRelSym : public SymbolRecord {
 
public:
 
  explicit DefRangeRegisterRelSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit DefRangeRegisterRelSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::DefRangeRegisterRelSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  // The flags implement this notional bitfield:
 
  //   uint16_t IsSubfield : 1;
 
  //   uint16_t Padding : 3;
 
  //   uint16_t OffsetInParent : 12;
 
  enum : uint16_t {
 
    IsSubfieldFlag = 1,
 
    OffsetInParentShift = 4,
 
  };
 
 
 
  bool hasSpilledUDTMember() const { return Hdr.Flags & IsSubfieldFlag; }
 
  uint16_t offsetInParent() const { return Hdr.Flags >> OffsetInParentShift; }
 
 
 
  uint32_t getRelocationOffset() const { return RecordOffset + sizeof(DefRangeRegisterRelHeader); }
 
 
 
  DefRangeRegisterRelHeader Hdr;
 
  LocalVariableAddrRange Range;
 
  std::vector<LocalVariableAddrGap> Gaps;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE
 
class DefRangeFramePointerRelFullScopeSym : public SymbolRecord {
 
public:
 
  explicit DefRangeFramePointerRelFullScopeSym(SymbolRecordKind Kind)
 
      : SymbolRecord(Kind) {}
 
  explicit DefRangeFramePointerRelFullScopeSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::DefRangeFramePointerRelFullScopeSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  int32_t Offset = 0;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_BLOCK32
 
class BlockSym : public SymbolRecord {
 
  static constexpr uint32_t RelocationOffset = 16;
 
 
 
public:
 
  explicit BlockSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit BlockSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::BlockSym), RecordOffset(RecordOffset) {}
 
 
 
  uint32_t getRelocationOffset() const {
 
    return RecordOffset + RelocationOffset;
 
  }
 
 
 
  uint32_t Parent = 0;
 
  uint32_t End = 0;
 
  uint32_t CodeSize = 0;
 
  uint32_t CodeOffset = 0;
 
  uint16_t Segment = 0;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_LABEL32
 
class LabelSym : public SymbolRecord {
 
  static constexpr uint32_t RelocationOffset = 4;
 
 
 
public:
 
  explicit LabelSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit LabelSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::LabelSym), RecordOffset(RecordOffset) {}
 
 
 
  uint32_t getRelocationOffset() const {
 
    return RecordOffset + RelocationOffset;
 
  }
 
 
 
  uint32_t CodeOffset = 0;
 
  uint16_t Segment = 0;
 
  ProcSymFlags Flags = ProcSymFlags::None;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_OBJNAME
 
class ObjNameSym : public SymbolRecord {
 
public:
 
  explicit ObjNameSym() : SymbolRecord(SymbolRecordKind::ObjNameSym) {}
 
  explicit ObjNameSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit ObjNameSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::ObjNameSym), RecordOffset(RecordOffset) {
 
  }
 
 
 
  uint32_t Signature = 0;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_ENVBLOCK
 
class EnvBlockSym : public SymbolRecord {
 
public:
 
  explicit EnvBlockSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit EnvBlockSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::EnvBlockSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  std::vector<StringRef> Fields;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_EXPORT
 
class ExportSym : public SymbolRecord {
 
public:
 
  explicit ExportSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit ExportSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::ExportSym), RecordOffset(RecordOffset) {}
 
 
 
  uint16_t Ordinal = 0;
 
  ExportFlags Flags = ExportFlags::None;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_FILESTATIC
 
class FileStaticSym : public SymbolRecord {
 
public:
 
  explicit FileStaticSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit FileStaticSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::FileStaticSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  TypeIndex Index;
 
  uint32_t ModFilenameOffset = 0;
 
  LocalSymFlags Flags = LocalSymFlags::None;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_COMPILE2
 
class Compile2Sym : public SymbolRecord {
 
public:
 
  explicit Compile2Sym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit Compile2Sym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::Compile2Sym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  CompileSym2Flags Flags = CompileSym2Flags::None;
 
  CPUType Machine;
 
  uint16_t VersionFrontendMajor = 0;
 
  uint16_t VersionFrontendMinor = 0;
 
  uint16_t VersionFrontendBuild = 0;
 
  uint16_t VersionBackendMajor = 0;
 
  uint16_t VersionBackendMinor = 0;
 
  uint16_t VersionBackendBuild = 0;
 
  StringRef Version;
 
  std::vector<StringRef> ExtraStrings;
 
 
 
  uint8_t getLanguage() const { return static_cast<uint32_t>(Flags) & 0xFF; }
 
  uint32_t getFlags() const { return static_cast<uint32_t>(Flags) & ~0xFF; }
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_COMPILE3
 
class Compile3Sym : public SymbolRecord {
 
public:
 
  Compile3Sym() : SymbolRecord(SymbolRecordKind::Compile3Sym) {}
 
  explicit Compile3Sym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit Compile3Sym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::Compile3Sym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  CompileSym3Flags Flags = CompileSym3Flags::None;
 
  CPUType Machine;
 
  uint16_t VersionFrontendMajor = 0;
 
  uint16_t VersionFrontendMinor = 0;
 
  uint16_t VersionFrontendBuild = 0;
 
  uint16_t VersionFrontendQFE = 0;
 
  uint16_t VersionBackendMajor = 0;
 
  uint16_t VersionBackendMinor = 0;
 
  uint16_t VersionBackendBuild = 0;
 
  uint16_t VersionBackendQFE = 0;
 
  StringRef Version;
 
 
 
  void setLanguage(SourceLanguage Lang) {
 
    Flags = CompileSym3Flags((uint32_t(Flags) & 0xFFFFFF00) | uint32_t(Lang));
 
  }
 
 
 
  SourceLanguage getLanguage() const {
 
    return static_cast<SourceLanguage>(static_cast<uint32_t>(Flags) & 0xFF);
 
  }
 
  CompileSym3Flags getFlags() const {
 
    return static_cast<CompileSym3Flags>(static_cast<uint32_t>(Flags) & ~0xFF);
 
  }
 
 
 
  bool hasOptimizations() const {
 
    return CompileSym3Flags::None !=
 
           (getFlags() & (CompileSym3Flags::PGO | CompileSym3Flags::LTCG));
 
  }
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_FRAMEPROC
 
class FrameProcSym : public SymbolRecord {
 
public:
 
  explicit FrameProcSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit FrameProcSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::FrameProcSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  uint32_t TotalFrameBytes = 0;
 
  uint32_t PaddingFrameBytes = 0;
 
  uint32_t OffsetToPadding = 0;
 
  uint32_t BytesOfCalleeSavedRegisters = 0;
 
  uint32_t OffsetOfExceptionHandler = 0;
 
  uint16_t SectionIdOfExceptionHandler = 0;
 
  FrameProcedureOptions Flags = FrameProcedureOptions::None;
 
 
 
  /// Extract the register this frame uses to refer to local variables.
 
  RegisterId getLocalFramePtrReg(CPUType CPU) const {
 
    return decodeFramePtrReg(
 
        EncodedFramePtrReg((uint32_t(Flags) >> 14U) & 0x3U), CPU);
 
  }
 
 
 
  /// Extract the register this frame uses to refer to parameters.
 
  RegisterId getParamFramePtrReg(CPUType CPU) const {
 
    return decodeFramePtrReg(
 
        EncodedFramePtrReg((uint32_t(Flags) >> 16U) & 0x3U), CPU);
 
  }
 
 
 
  uint32_t RecordOffset = 0;
 
 
 
private:
 
};
 
 
 
// S_CALLSITEINFO
 
class CallSiteInfoSym : public SymbolRecord {
 
  static constexpr uint32_t RelocationOffset = 4;
 
 
 
public:
 
  explicit CallSiteInfoSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit CallSiteInfoSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::CallSiteInfoSym) {}
 
 
 
  uint32_t getRelocationOffset() const {
 
    return RecordOffset + RelocationOffset;
 
  }
 
 
 
  uint32_t CodeOffset = 0;
 
  uint16_t Segment = 0;
 
  TypeIndex Type;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_HEAPALLOCSITE
 
class HeapAllocationSiteSym : public SymbolRecord {
 
  static constexpr uint32_t RelocationOffset = 4;
 
 
 
public:
 
  explicit HeapAllocationSiteSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit HeapAllocationSiteSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::HeapAllocationSiteSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  uint32_t getRelocationOffset() const {
 
    return RecordOffset + RelocationOffset;
 
  }
 
 
 
  uint32_t CodeOffset = 0;
 
  uint16_t Segment = 0;
 
  uint16_t CallInstructionSize = 0;
 
  TypeIndex Type;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_FRAMECOOKIE
 
class FrameCookieSym : public SymbolRecord {
 
  static constexpr uint32_t RelocationOffset = 4;
 
 
 
public:
 
  explicit FrameCookieSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit FrameCookieSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::FrameCookieSym) {}
 
 
 
  uint32_t getRelocationOffset() const {
 
    return RecordOffset + RelocationOffset;
 
  }
 
 
 
  uint32_t CodeOffset = 0;
 
  uint16_t Register = 0;
 
  FrameCookieKind CookieKind;
 
  uint8_t Flags = 0;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_UDT, S_COBOLUDT
 
class UDTSym : public SymbolRecord {
 
public:
 
  explicit UDTSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit UDTSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::UDTSym) {}
 
 
 
  TypeIndex Type;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_BUILDINFO
 
class BuildInfoSym : public SymbolRecord {
 
public:
 
  explicit BuildInfoSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit BuildInfoSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::BuildInfoSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  TypeIndex BuildId;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_BPREL32
 
class BPRelativeSym : public SymbolRecord {
 
public:
 
  explicit BPRelativeSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit BPRelativeSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::BPRelativeSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  int32_t Offset = 0;
 
  TypeIndex Type;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_REGREL32
 
class RegRelativeSym : public SymbolRecord {
 
public:
 
  explicit RegRelativeSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit RegRelativeSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::RegRelativeSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  uint32_t Offset = 0;
 
  TypeIndex Type;
 
  RegisterId Register;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_CONSTANT, S_MANCONSTANT
 
class ConstantSym : public SymbolRecord {
 
public:
 
  explicit ConstantSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit ConstantSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::ConstantSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  TypeIndex Type;
 
  APSInt Value;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_LDATA32, S_GDATA32, S_LMANDATA, S_GMANDATA
 
class DataSym : public SymbolRecord {
 
  static constexpr uint32_t RelocationOffset = 8;
 
 
 
public:
 
  explicit DataSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit DataSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::DataSym), RecordOffset(RecordOffset) {}
 
 
 
  uint32_t getRelocationOffset() const {
 
    return RecordOffset + RelocationOffset;
 
  }
 
 
 
  TypeIndex Type;
 
  uint32_t DataOffset = 0;
 
  uint16_t Segment = 0;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_LTHREAD32, S_GTHREAD32
 
class ThreadLocalDataSym : public SymbolRecord {
 
  static constexpr uint32_t RelocationOffset = 8;
 
 
 
public:
 
  explicit ThreadLocalDataSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit ThreadLocalDataSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::ThreadLocalDataSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  uint32_t getRelocationOffset() const {
 
    return RecordOffset + RelocationOffset;
 
  }
 
 
 
  TypeIndex Type;
 
  uint32_t DataOffset = 0;
 
  uint16_t Segment = 0;
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_UNAMESPACE
 
class UsingNamespaceSym : public SymbolRecord {
 
public:
 
  explicit UsingNamespaceSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit UsingNamespaceSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::UsingNamespaceSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  StringRef Name;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
// S_ANNOTATION
 
class AnnotationSym : public SymbolRecord {
 
public:
 
  explicit AnnotationSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
 
  explicit AnnotationSym(uint32_t RecordOffset)
 
      : SymbolRecord(SymbolRecordKind::AnnotationSym),
 
        RecordOffset(RecordOffset) {}
 
 
 
  uint32_t CodeOffset = 0;
 
  uint16_t Segment = 0;
 
  std::vector<StringRef> Strings;
 
 
 
  uint32_t RecordOffset = 0;
 
};
 
 
 
Expected<CVSymbol> readSymbolFromStream(BinaryStreamRef Stream,
 
                                        uint32_t Offset);
 
 
 
} // end namespace codeview
 
} // end namespace llvm
 
 
 
#endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H