1013 lines
28 KiB
C
1013 lines
28 KiB
C
|
//===- 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;
|
||
|
};
|
||
|
|
||
|
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
|