| //===- 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/Optional.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.getValue(); |
| } |
| |
| 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.hasValue()) |
| 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; |
| } |
| |
| 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; |
| }; |
| |
| // 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; |
| }; |
| |
| using CVSymbol = CVRecord<SymbolKind>; |
| using CVSymbolArray = VarStreamArray<CVSymbol>; |
| |
| Expected<CVSymbol> readSymbolFromStream(BinaryStreamRef Stream, |
| uint32_t Offset); |
| |
| } // end namespace codeview |
| } // end namespace llvm |
| |
| #endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H |