summaryrefslogtreecommitdiff
path: root/include/llvm/DebugInfo/CodeView
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/DebugInfo/CodeView')
-rw-r--r--include/llvm/DebugInfo/CodeView/ByteStream.h58
-rw-r--r--include/llvm/DebugInfo/CodeView/CVRecord.h56
-rw-r--r--include/llvm/DebugInfo/CodeView/CVSymbolTypes.def258
-rw-r--r--include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h103
-rw-r--r--include/llvm/DebugInfo/CodeView/CVTypeVisitor.h44
-rw-r--r--include/llvm/DebugInfo/CodeView/CodeView.h509
-rw-r--r--include/llvm/DebugInfo/CodeView/CodeViewError.h44
-rw-r--r--include/llvm/DebugInfo/CodeView/EnumTables.h42
-rw-r--r--include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h37
-rw-r--r--include/llvm/DebugInfo/CodeView/Line.h50
-rw-r--r--include/llvm/DebugInfo/CodeView/ListRecordBuilder.h22
-rw-r--r--include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h48
-rw-r--r--include/llvm/DebugInfo/CodeView/ModuleSubstream.h87
-rw-r--r--include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h121
-rw-r--r--include/llvm/DebugInfo/CodeView/RecordSerialization.h278
-rw-r--r--include/llvm/DebugInfo/CodeView/StreamArray.h275
-rw-r--r--include/llvm/DebugInfo/CodeView/StreamInterface.h55
-rw-r--r--include/llvm/DebugInfo/CodeView/StreamReader.h111
-rw-r--r--include/llvm/DebugInfo/CodeView/StreamRef.h104
-rw-r--r--include/llvm/DebugInfo/CodeView/StreamWriter.h86
-rw-r--r--include/llvm/DebugInfo/CodeView/SymbolDumpDelegate.h37
-rw-r--r--include/llvm/DebugInfo/CodeView/SymbolDumper.h54
-rw-r--r--include/llvm/DebugInfo/CodeView/SymbolRecord.h1452
-rw-r--r--include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h33
-rw-r--r--include/llvm/DebugInfo/CodeView/TypeDumper.h105
-rw-r--r--include/llvm/DebugInfo/CodeView/TypeIndex.h76
-rw-r--r--include/llvm/DebugInfo/CodeView/TypeRecord.h1024
-rw-r--r--include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h17
-rw-r--r--include/llvm/DebugInfo/CodeView/TypeRecords.def252
-rw-r--r--include/llvm/DebugInfo/CodeView/TypeStreamMerger.h26
-rw-r--r--include/llvm/DebugInfo/CodeView/TypeSymbolEmitter.h3
-rw-r--r--include/llvm/DebugInfo/CodeView/TypeTableBuilder.h26
-rw-r--r--include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h63
33 files changed, 5237 insertions, 319 deletions
diff --git a/include/llvm/DebugInfo/CodeView/ByteStream.h b/include/llvm/DebugInfo/CodeView/ByteStream.h
new file mode 100644
index 0000000000000..f398c93723e7a
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/ByteStream.h
@@ -0,0 +1,58 @@
+//===- ByteStream.h - Reads stream data from a byte sequence ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_BYTESTREAM_H
+#define LLVM_DEBUGINFO_CODEVIEW_BYTESTREAM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/CodeView/StreamInterface.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+#include <memory>
+#include <type_traits>
+
+namespace llvm {
+namespace codeview {
+class StreamReader;
+
+template <bool Writable = false> class ByteStream : public StreamInterface {
+ typedef typename std::conditional<Writable, MutableArrayRef<uint8_t>,
+ ArrayRef<uint8_t>>::type ArrayType;
+
+public:
+ ByteStream() {}
+ explicit ByteStream(ArrayType Data) : Data(Data) {}
+ ~ByteStream() override {}
+
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) const override;
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) const override;
+
+ Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) const override;
+
+ uint32_t getLength() const override;
+
+ Error commit() const override;
+
+ ArrayRef<uint8_t> data() const { return Data; }
+ StringRef str() const;
+
+private:
+ ArrayType Data;
+};
+
+extern template class ByteStream<true>;
+extern template class ByteStream<false>;
+
+} // end namespace pdb
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_BYTESTREAM_H
diff --git a/include/llvm/DebugInfo/CodeView/CVRecord.h b/include/llvm/DebugInfo/CodeView/CVRecord.h
new file mode 100644
index 0000000000000..dba359fcbe82e
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/CVRecord.h
@@ -0,0 +1,56 @@
+//===- RecordIterator.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H
+#define LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+#include "llvm/DebugInfo/CodeView/StreamInterface.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/Support/Endian.h"
+
+namespace llvm {
+namespace codeview {
+
+template <typename Kind> struct CVRecord {
+ uint32_t Length;
+ Kind Type;
+ ArrayRef<uint8_t> Data;
+ ArrayRef<uint8_t> RawData;
+};
+
+template <typename Kind> struct VarStreamArrayExtractor<CVRecord<Kind>> {
+ Error operator()(StreamRef Stream, uint32_t &Len,
+ CVRecord<Kind> &Item) const {
+ const RecordPrefix *Prefix = nullptr;
+ StreamReader Reader(Stream);
+ uint32_t Offset = Reader.getOffset();
+
+ if (auto EC = Reader.readObject(Prefix))
+ return EC;
+ Item.Length = Prefix->RecordLen;
+ if (Item.Length < 2)
+ return make_error<CodeViewError>(cv_error_code::corrupt_record);
+ Item.Type = static_cast<Kind>(uint16_t(Prefix->RecordKind));
+
+ Reader.setOffset(Offset);
+ if (auto EC =
+ Reader.readBytes(Item.RawData, Item.Length + sizeof(uint16_t)))
+ return EC;
+ Item.Data = Item.RawData.slice(sizeof(RecordPrefix));
+ Len = Prefix->RecordLen + 2;
+ return Error::success();
+ }
+};
+}
+}
+
+#endif
diff --git a/include/llvm/DebugInfo/CodeView/CVSymbolTypes.def b/include/llvm/DebugInfo/CodeView/CVSymbolTypes.def
new file mode 100644
index 0000000000000..32813d861d909
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/CVSymbolTypes.def
@@ -0,0 +1,258 @@
+//===-- CVLeafTypes.def - All CodeView leaf types ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// See LEAF_ENUM_e in cvinfo.h. This should match the constants there.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CV_SYMBOL
+#define CV_SYMBOL(ename, value)
+#endif
+
+#ifndef SYMBOL_RECORD
+#define SYMBOL_RECORD(lf_ename, value, name) CV_SYMBOL(lf_ename, value)
+#endif
+
+#ifndef SYMBOL_RECORD_ALIAS
+#define SYMBOL_RECORD_ALIAS(lf_ename, value, name, alias_name) \
+ SYMBOL_RECORD(lf_ename, value, name)
+#endif
+
+// 16 bit symbol types. Not very useful, provided only for reference.
+CV_SYMBOL(S_COMPILE , 0x0001)
+CV_SYMBOL(S_REGISTER_16t , 0x0002)
+CV_SYMBOL(S_CONSTANT_16t , 0x0003)
+CV_SYMBOL(S_UDT_16t , 0x0004)
+CV_SYMBOL(S_SSEARCH , 0x0005)
+CV_SYMBOL(S_SKIP , 0x0007)
+CV_SYMBOL(S_CVRESERVE , 0x0008)
+CV_SYMBOL(S_OBJNAME_ST , 0x0009)
+CV_SYMBOL(S_ENDARG , 0x000a)
+CV_SYMBOL(S_COBOLUDT_16t , 0x000b)
+CV_SYMBOL(S_MANYREG_16t , 0x000c)
+CV_SYMBOL(S_RETURN , 0x000d)
+CV_SYMBOL(S_ENTRYTHIS , 0x000e)
+CV_SYMBOL(S_BPREL16 , 0x0100)
+CV_SYMBOL(S_LDATA16 , 0x0101)
+CV_SYMBOL(S_GDATA16 , 0x0102)
+CV_SYMBOL(S_PUB16 , 0x0103)
+CV_SYMBOL(S_LPROC16 , 0x0104)
+CV_SYMBOL(S_GPROC16 , 0x0105)
+CV_SYMBOL(S_THUNK16 , 0x0106)
+CV_SYMBOL(S_BLOCK16 , 0x0107)
+CV_SYMBOL(S_WITH16 , 0x0108)
+CV_SYMBOL(S_LABEL16 , 0x0109)
+CV_SYMBOL(S_CEXMODEL16 , 0x010a)
+CV_SYMBOL(S_VFTABLE16 , 0x010b)
+CV_SYMBOL(S_REGREL16 , 0x010c)
+CV_SYMBOL(S_BPREL32_16t , 0x0200)
+CV_SYMBOL(S_LDATA32_16t , 0x0201)
+CV_SYMBOL(S_GDATA32_16t , 0x0202)
+CV_SYMBOL(S_PUB32_16t , 0x0203)
+CV_SYMBOL(S_LPROC32_16t , 0x0204)
+CV_SYMBOL(S_GPROC32_16t , 0x0205)
+CV_SYMBOL(S_THUNK32_ST , 0x0206)
+CV_SYMBOL(S_BLOCK32_ST , 0x0207)
+CV_SYMBOL(S_WITH32_ST , 0x0208)
+CV_SYMBOL(S_LABEL32_ST , 0x0209)
+CV_SYMBOL(S_CEXMODEL32 , 0x020a)
+CV_SYMBOL(S_VFTABLE32_16t , 0x020b)
+CV_SYMBOL(S_REGREL32_16t , 0x020c)
+CV_SYMBOL(S_LTHREAD32_16t , 0x020d)
+CV_SYMBOL(S_GTHREAD32_16t , 0x020e)
+CV_SYMBOL(S_SLINK32 , 0x020f)
+CV_SYMBOL(S_LPROCMIPS_16t , 0x0300)
+CV_SYMBOL(S_GPROCMIPS_16t , 0x0301)
+CV_SYMBOL(S_PROCREF_ST , 0x0400)
+CV_SYMBOL(S_DATAREF_ST , 0x0401)
+CV_SYMBOL(S_ALIGN , 0x0402)
+CV_SYMBOL(S_LPROCREF_ST , 0x0403)
+CV_SYMBOL(S_OEM , 0x0404)
+
+// All post 16 bit symbol types have the 0x1000 bit set.
+CV_SYMBOL(S_TI16_MAX , 0x1000)
+
+// Mostly unused "start" symbol types.
+CV_SYMBOL(S_REGISTER_ST , 0x1001)
+CV_SYMBOL(S_CONSTANT_ST , 0x1002)
+CV_SYMBOL(S_UDT_ST , 0x1003)
+CV_SYMBOL(S_COBOLUDT_ST , 0x1004)
+CV_SYMBOL(S_MANYREG_ST , 0x1005)
+CV_SYMBOL(S_BPREL32_ST , 0x1006)
+CV_SYMBOL(S_LDATA32_ST , 0x1007)
+CV_SYMBOL(S_GDATA32_ST , 0x1008)
+CV_SYMBOL(S_PUB32_ST , 0x1009)
+CV_SYMBOL(S_LPROC32_ST , 0x100a)
+CV_SYMBOL(S_GPROC32_ST , 0x100b)
+CV_SYMBOL(S_VFTABLE32 , 0x100c)
+CV_SYMBOL(S_REGREL32_ST , 0x100d)
+CV_SYMBOL(S_LTHREAD32_ST , 0x100e)
+CV_SYMBOL(S_GTHREAD32_ST , 0x100f)
+CV_SYMBOL(S_LPROCMIPS_ST , 0x1010)
+CV_SYMBOL(S_GPROCMIPS_ST , 0x1011)
+
+CV_SYMBOL(S_COMPILE2_ST , 0x1013)
+CV_SYMBOL(S_MANYREG2_ST , 0x1014)
+CV_SYMBOL(S_LPROCIA64_ST , 0x1015)
+CV_SYMBOL(S_GPROCIA64_ST , 0x1016)
+CV_SYMBOL(S_LOCALSLOT_ST , 0x1017)
+CV_SYMBOL(S_PARAMSLOT_ST , 0x1018)
+CV_SYMBOL(S_ANNOTATION , 0x1019)
+CV_SYMBOL(S_GMANPROC_ST , 0x101a)
+CV_SYMBOL(S_LMANPROC_ST , 0x101b)
+CV_SYMBOL(S_RESERVED1 , 0x101c)
+CV_SYMBOL(S_RESERVED2 , 0x101d)
+CV_SYMBOL(S_RESERVED3 , 0x101e)
+CV_SYMBOL(S_RESERVED4 , 0x101f)
+CV_SYMBOL(S_LMANDATA_ST , 0x1020)
+CV_SYMBOL(S_GMANDATA_ST , 0x1021)
+CV_SYMBOL(S_MANFRAMEREL_ST, 0x1022)
+CV_SYMBOL(S_MANREGISTER_ST, 0x1023)
+CV_SYMBOL(S_MANSLOT_ST , 0x1024)
+CV_SYMBOL(S_MANMANYREG_ST , 0x1025)
+CV_SYMBOL(S_MANREGREL_ST , 0x1026)
+CV_SYMBOL(S_MANMANYREG2_ST, 0x1027)
+CV_SYMBOL(S_MANTYPREF , 0x1028)
+CV_SYMBOL(S_UNAMESPACE_ST , 0x1029)
+
+// End of S_*_ST symbols, which do not appear to be generated by modern
+// compilers.
+CV_SYMBOL(S_ST_MAX , 0x1100)
+
+
+CV_SYMBOL(S_WITH32 , 0x1104)
+CV_SYMBOL(S_MANYREG , 0x110a)
+CV_SYMBOL(S_LPROCMIPS , 0x1114)
+CV_SYMBOL(S_GPROCMIPS , 0x1115)
+CV_SYMBOL(S_MANYREG2 , 0x1117)
+CV_SYMBOL(S_LPROCIA64 , 0x1118)
+CV_SYMBOL(S_GPROCIA64 , 0x1119)
+CV_SYMBOL(S_LOCALSLOT , 0x111a)
+CV_SYMBOL(S_PARAMSLOT , 0x111b)
+
+// Managed code symbols.
+CV_SYMBOL(S_MANFRAMEREL , 0x111e)
+CV_SYMBOL(S_MANREGISTER , 0x111f)
+CV_SYMBOL(S_MANSLOT , 0x1120)
+CV_SYMBOL(S_MANMANYREG , 0x1121)
+CV_SYMBOL(S_MANREGREL , 0x1122)
+CV_SYMBOL(S_MANMANYREG2 , 0x1123)
+CV_SYMBOL(S_UNAMESPACE , 0x1124)
+CV_SYMBOL(S_DATAREF , 0x1126)
+CV_SYMBOL(S_ANNOTATIONREF , 0x1128)
+CV_SYMBOL(S_TOKENREF , 0x1129)
+CV_SYMBOL(S_GMANPROC , 0x112a)
+CV_SYMBOL(S_LMANPROC , 0x112b)
+CV_SYMBOL(S_ATTR_FRAMEREL , 0x112e)
+CV_SYMBOL(S_ATTR_REGISTER , 0x112f)
+CV_SYMBOL(S_ATTR_REGREL , 0x1130)
+CV_SYMBOL(S_ATTR_MANYREG , 0x1131)
+
+
+CV_SYMBOL(S_SEPCODE , 0x1132)
+CV_SYMBOL(S_LOCAL_2005 , 0x1133)
+CV_SYMBOL(S_DEFRANGE_2005 , 0x1134)
+CV_SYMBOL(S_DEFRANGE2_2005, 0x1135)
+CV_SYMBOL(S_DISCARDED , 0x113b)
+
+// Current symbol types for most procedures as of this writing.
+CV_SYMBOL(S_LPROCMIPS_ID , 0x1148)
+CV_SYMBOL(S_GPROCMIPS_ID , 0x1149)
+CV_SYMBOL(S_LPROCIA64_ID , 0x114a)
+CV_SYMBOL(S_GPROCIA64_ID , 0x114b)
+
+CV_SYMBOL(S_DEFRANGE_HLSL , 0x1150)
+CV_SYMBOL(S_GDATA_HLSL , 0x1151)
+CV_SYMBOL(S_LDATA_HLSL , 0x1152)
+CV_SYMBOL(S_LOCAL_DPC_GROUPSHARED, 0x1154)
+CV_SYMBOL(S_DEFRANGE_DPC_PTR_TAG, 0x1157)
+CV_SYMBOL(S_DPC_SYM_TAG_MAP, 0x1158)
+CV_SYMBOL(S_ARMSWITCHTABLE , 0x1159)
+CV_SYMBOL(S_POGODATA , 0x115c)
+CV_SYMBOL(S_INLINESITE2 , 0x115d)
+CV_SYMBOL(S_MOD_TYPEREF , 0x115f)
+CV_SYMBOL(S_REF_MINIPDB , 0x1160)
+CV_SYMBOL(S_PDBMAP , 0x1161)
+CV_SYMBOL(S_GDATA_HLSL32 , 0x1162)
+CV_SYMBOL(S_LDATA_HLSL32 , 0x1163)
+CV_SYMBOL(S_GDATA_HLSL32_EX, 0x1164)
+CV_SYMBOL(S_LDATA_HLSL32_EX, 0x1165)
+
+// Known symbol types
+SYMBOL_RECORD(S_END , 0x0006, ScopeEndSym)
+SYMBOL_RECORD_ALIAS(S_INLINESITE_END , 0x114e, InlineSiteEnd, ScopeEndSym)
+SYMBOL_RECORD_ALIAS(S_PROC_ID_END , 0x114f, ProcEnd, ScopeEndSym)
+
+SYMBOL_RECORD(S_THUNK32 , 0x1102, Thunk32Sym)
+SYMBOL_RECORD(S_TRAMPOLINE , 0x112c, TrampolineSym)
+SYMBOL_RECORD(S_SECTION , 0x1136, SectionSym)
+SYMBOL_RECORD(S_COFFGROUP , 0x1137, CoffGroupSym)
+SYMBOL_RECORD(S_EXPORT , 0x1138, ExportSym)
+
+SYMBOL_RECORD(S_LPROC32 , 0x110f, ProcSym)
+SYMBOL_RECORD_ALIAS(S_GPROC32 , 0x1110, GlobalProcSym, ProcSym)
+SYMBOL_RECORD_ALIAS(S_LPROC32_ID , 0x1146, ProcIdSym, ProcSym)
+SYMBOL_RECORD_ALIAS(S_GPROC32_ID , 0x1147, GlobalProcIdSym, ProcSym)
+SYMBOL_RECORD_ALIAS(S_LPROC32_DPC , 0x1155, DPCProcSym, ProcSym)
+SYMBOL_RECORD_ALIAS(S_LPROC32_DPC_ID , 0x1156, DPCProcIdSym, ProcSym)
+
+SYMBOL_RECORD(S_REGISTER , 0x1106, RegisterSym)
+SYMBOL_RECORD(S_PUB32 , 0x110e, PublicSym32)
+
+SYMBOL_RECORD(S_PROCREF , 0x1125, ProcRefSym)
+SYMBOL_RECORD_ALIAS(S_LPROCREF, 0x1127, LocalProcRef, ProcRefSym)
+
+
+SYMBOL_RECORD(S_ENVBLOCK , 0x113d, EnvBlockSym)
+
+SYMBOL_RECORD(S_INLINESITE , 0x114d, InlineSiteSym)
+SYMBOL_RECORD(S_LOCAL , 0x113e, LocalSym)
+SYMBOL_RECORD(S_DEFRANGE , 0x113f, DefRangeSym)
+SYMBOL_RECORD(S_DEFRANGE_SUBFIELD, 0x1140, DefRangeSubfieldSym)
+SYMBOL_RECORD(S_DEFRANGE_REGISTER, 0x1141, DefRangeRegisterSym)
+SYMBOL_RECORD(S_DEFRANGE_FRAMEPOINTER_REL, 0x1142, DefRangeFramePointerRelSym)
+SYMBOL_RECORD(S_DEFRANGE_SUBFIELD_REGISTER, 0x1143, DefRangeSubfieldRegisterSym)
+SYMBOL_RECORD(S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE, 0x1144, DefRangeFramePointerRelFullScopeSym)
+SYMBOL_RECORD(S_DEFRANGE_REGISTER_REL, 0x1145, DefRangeRegisterRelSym)
+SYMBOL_RECORD(S_BLOCK32 , 0x1103, BlockSym)
+SYMBOL_RECORD(S_LABEL32 , 0x1105, LabelSym)
+SYMBOL_RECORD(S_OBJNAME , 0x1101, ObjNameSym)
+SYMBOL_RECORD(S_COMPILE2 , 0x1116, Compile2Sym)
+SYMBOL_RECORD(S_COMPILE3 , 0x113c, Compile3Sym)
+SYMBOL_RECORD(S_FRAMEPROC , 0x1012, FrameProcSym)
+SYMBOL_RECORD(S_CALLSITEINFO , 0x1139, CallSiteInfoSym)
+SYMBOL_RECORD(S_FILESTATIC , 0x1153, FileStaticSym)
+SYMBOL_RECORD(S_HEAPALLOCSITE , 0x115e, HeapAllocationSiteSym)
+SYMBOL_RECORD(S_FRAMECOOKIE , 0x113a, FrameCookieSym)
+
+SYMBOL_RECORD(S_CALLEES , 0x115a, CallerSym)
+SYMBOL_RECORD_ALIAS(S_CALLERS , 0x115b, CalleeSym, CallerSym)
+
+SYMBOL_RECORD(S_UDT , 0x1108, UDTSym)
+SYMBOL_RECORD_ALIAS(S_COBOLUDT , 0x1109, CobolUDT, UDTSym)
+
+SYMBOL_RECORD(S_BUILDINFO , 0x114c, BuildInfoSym)
+SYMBOL_RECORD(S_BPREL32 , 0x110b, BPRelativeSym)
+SYMBOL_RECORD(S_REGREL32 , 0x1111, RegRelativeSym)
+
+SYMBOL_RECORD(S_CONSTANT , 0x1107, ConstantSym)
+SYMBOL_RECORD_ALIAS(S_MANCONSTANT , 0x112d, ManagedConstant, ConstantSym)
+
+SYMBOL_RECORD(S_LDATA32 , 0x110c, DataSym)
+SYMBOL_RECORD_ALIAS(S_GDATA32 , 0x110d, GlobalData, DataSym)
+SYMBOL_RECORD_ALIAS(S_LMANDATA , 0x111c, ManagedLocalData, DataSym)
+SYMBOL_RECORD_ALIAS(S_GMANDATA , 0x111d, ManagedGlobalData, DataSym)
+
+SYMBOL_RECORD(S_LTHREAD32 , 0x1112, ThreadLocalDataSym)
+SYMBOL_RECORD_ALIAS(S_GTHREAD32 , 0x1113, GlobalTLS, ThreadLocalDataSym)
+
+
+#undef CV_SYMBOL
+#undef SYMBOL_RECORD
+#undef SYMBOL_RECORD_ALIAS
diff --git a/include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h b/include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h
new file mode 100644
index 0000000000000..7c88956c984ed
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h
@@ -0,0 +1,103 @@
+//===- CVSymbolVisitor.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_CVSYMBOLVISITOR_H
+#define LLVM_DEBUGINFO_CODEVIEW_CVSYMBOLVISITOR_H
+
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h"
+#include "llvm/Support/ErrorOr.h"
+
+namespace llvm {
+namespace codeview {
+
+template <typename Derived> class CVSymbolVisitor {
+public:
+ CVSymbolVisitor(SymbolVisitorDelegate *Delegate) : Delegate(Delegate) {}
+
+ bool hadError() const { return HadError; }
+
+ template <typename T>
+ bool consumeObject(ArrayRef<uint8_t> &Data, const T *&Res) {
+ if (Data.size() < sizeof(*Res)) {
+ HadError = true;
+ return false;
+ }
+ Res = reinterpret_cast<const T *>(Data.data());
+ Data = Data.drop_front(sizeof(*Res));
+ return true;
+ }
+
+/// Actions to take on known symbols. By default, they do nothing. Visit methods
+/// for member records take the FieldData by non-const reference and are
+/// expected to consume the trailing bytes used by the field.
+/// FIXME: Make the visitor interpret the trailing bytes so that clients don't
+/// need to.
+#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
+ void visit##Name(SymbolRecordKind Kind, Name &Record) {}
+#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "CVSymbolTypes.def"
+
+ void visitSymbolRecord(const CVRecord<SymbolKind> &Record) {
+ ArrayRef<uint8_t> Data = Record.Data;
+ auto *DerivedThis = static_cast<Derived *>(this);
+ DerivedThis->visitSymbolBegin(Record.Type, Data);
+ uint32_t RecordOffset = Delegate ? Delegate->getRecordOffset(Data) : 0;
+ switch (Record.Type) {
+ default:
+ DerivedThis->visitUnknownSymbol(Record.Type, Data);
+ break;
+#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: { \
+ SymbolRecordKind RK = static_cast<SymbolRecordKind>(EnumName); \
+ auto Result = Name::deserialize(RK, RecordOffset, Data); \
+ if (Result.getError()) \
+ return parseError(); \
+ DerivedThis->visit##Name(Record.Type, *Result); \
+ break; \
+ }
+#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
+ SYMBOL_RECORD(EnumVal, EnumVal, AliasName)
+#include "CVSymbolTypes.def"
+ }
+ DerivedThis->visitSymbolEnd(Record.Type, Record.Data);
+ }
+
+ /// Visits the symbol records in Data. Sets the error flag on parse failures.
+ void visitSymbolStream(const CVSymbolArray &Symbols) {
+ for (const auto &I : Symbols) {
+ visitSymbolRecord(I);
+ if (hadError())
+ break;
+ }
+ }
+
+ /// Action to take on unknown symbols. By default, they are ignored.
+ void visitUnknownSymbol(SymbolKind Kind, ArrayRef<uint8_t> Data) {}
+
+ /// Paired begin/end actions for all symbols. Receives all record data,
+ /// including the fixed-length record prefix.
+ void visitSymbolBegin(SymbolKind Leaf, ArrayRef<uint8_t> RecordData) {}
+ void visitSymbolEnd(SymbolKind Leaf, ArrayRef<uint8_t> OriginalSymData) {}
+
+ /// Helper for returning from a void function when the stream is corrupted.
+ void parseError() { HadError = true; }
+
+private:
+ SymbolVisitorDelegate *Delegate;
+ /// Whether a symbol stream parsing error was encountered.
+ bool HadError = false;
+};
+
+} // end namespace codeview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_CVSYMBOLVISITOR_H
diff --git a/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h
new file mode 100644
index 0000000000000..930ac6930c243
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h
@@ -0,0 +1,44 @@
+//===- CVTypeVisitor.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H
+#define LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H
+
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace codeview {
+
+class CVTypeVisitor {
+public:
+ explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
+
+ Error visitTypeRecord(const CVRecord<TypeLeafKind> &Record);
+
+ /// Visits the type records in Data. Sets the error flag on parse failures.
+ Error visitTypeStream(const CVTypeArray &Types);
+
+ Error skipPadding(ArrayRef<uint8_t> &Data);
+
+ /// Visits individual member records of a field list record. Member records do
+ /// not describe their own length, and need special handling.
+ Error visitFieldList(const CVRecord<TypeLeafKind> &Record);
+
+private:
+ /// The interface to the class that gets notified of each visitation.
+ TypeVisitorCallbacks &Callbacks;
+};
+
+} // end namespace codeview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H
diff --git a/include/llvm/DebugInfo/CodeView/CodeView.h b/include/llvm/DebugInfo/CodeView/CodeView.h
index 7728120d68de4..1ee203b4f8fab 100644
--- a/include/llvm/DebugInfo/CodeView/CodeView.h
+++ b/include/llvm/DebugInfo/CodeView/CodeView.h
@@ -11,10 +11,156 @@
#define LLVM_DEBUGINFO_CODEVIEW_CODEVIEW_H
#include <cinttypes>
+#include <type_traits>
namespace llvm {
namespace codeview {
+/// Distinguishes individual records in .debug$T section or PDB type stream. The
+/// documentation and headers talk about this as the "leaf" type.
+enum class TypeRecordKind : uint16_t {
+#define TYPE_RECORD(lf_ename, value, name) name = value,
+#include "TypeRecords.def"
+ // FIXME: Add serialization support
+ FieldList = 0x1203,
+};
+
+/// Duplicate copy of the above enum, but using the official CV names. Useful
+/// for reference purposes and when dealing with unknown record types.
+enum TypeLeafKind : uint16_t {
+#define CV_TYPE(name, val) name = val,
+#include "TypeRecords.def"
+};
+
+/// Distinguishes individual records in the Symbols subsection of a .debug$S
+/// section. Equivalent to SYM_ENUM_e in cvinfo.h.
+enum class SymbolRecordKind : uint16_t {
+#define SYMBOL_RECORD(lf_ename, value, name) name = value,
+#include "CVSymbolTypes.def"
+};
+
+/// Duplicate copy of the above enum, but using the official CV names. Useful
+/// for reference purposes and when dealing with unknown record types.
+enum SymbolKind : uint16_t {
+#define CV_SYMBOL(name, val) name = val,
+#include "CVSymbolTypes.def"
+};
+
+#define CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(Class) \
+ inline Class operator|(Class a, Class b) { \
+ return static_cast<Class>( \
+ static_cast<std::underlying_type<Class>::type>(a) | \
+ static_cast<std::underlying_type<Class>::type>(b)); \
+ } \
+ inline Class operator&(Class a, Class b) { \
+ return static_cast<Class>( \
+ static_cast<std::underlying_type<Class>::type>(a) & \
+ static_cast<std::underlying_type<Class>::type>(b)); \
+ } \
+ inline Class operator~(Class a) { \
+ return static_cast<Class>( \
+ ~static_cast<std::underlying_type<Class>::type>(a)); \
+ } \
+ inline Class &operator|=(Class &a, Class b) { \
+ a = a | b; \
+ return a; \
+ } \
+ inline Class &operator&=(Class &a, Class b) { \
+ a = a & b; \
+ return a; \
+ }
+
+/// These values correspond to the CV_CPU_TYPE_e enumeration, and are documented
+/// here: https://msdn.microsoft.com/en-us/library/b2fc64ek.aspx
+enum class CPUType : uint16_t {
+ Intel8080 = 0x0,
+ Intel8086 = 0x1,
+ Intel80286 = 0x2,
+ Intel80386 = 0x3,
+ Intel80486 = 0x4,
+ Pentium = 0x5,
+ PentiumPro = 0x6,
+ Pentium3 = 0x7,
+ MIPS = 0x10,
+ MIPS16 = 0x11,
+ MIPS32 = 0x12,
+ MIPS64 = 0x13,
+ MIPSI = 0x14,
+ MIPSII = 0x15,
+ MIPSIII = 0x16,
+ MIPSIV = 0x17,
+ MIPSV = 0x18,
+ M68000 = 0x20,
+ M68010 = 0x21,
+ M68020 = 0x22,
+ M68030 = 0x23,
+ M68040 = 0x24,
+ Alpha = 0x30,
+ Alpha21164 = 0x31,
+ Alpha21164A = 0x32,
+ Alpha21264 = 0x33,
+ Alpha21364 = 0x34,
+ PPC601 = 0x40,
+ PPC603 = 0x41,
+ PPC604 = 0x42,
+ PPC620 = 0x43,
+ PPCFP = 0x44,
+ PPCBE = 0x45,
+ SH3 = 0x50,
+ SH3E = 0x51,
+ SH3DSP = 0x52,
+ SH4 = 0x53,
+ SHMedia = 0x54,
+ ARM3 = 0x60,
+ ARM4 = 0x61,
+ ARM4T = 0x62,
+ ARM5 = 0x63,
+ ARM5T = 0x64,
+ ARM6 = 0x65,
+ ARM_XMAC = 0x66,
+ ARM_WMMX = 0x67,
+ ARM7 = 0x68,
+ Omni = 0x70,
+ Ia64 = 0x80,
+ Ia64_2 = 0x81,
+ CEE = 0x90,
+ AM33 = 0xa0,
+ M32R = 0xb0,
+ TriCore = 0xc0,
+ X64 = 0xd0,
+ EBC = 0xe0,
+ Thumb = 0xf0,
+ ARMNT = 0xf4,
+ D3D11_Shader = 0x100,
+};
+
+/// These values correspond to the CV_CFL_LANG enumeration, and are documented
+/// here: https://msdn.microsoft.com/en-us/library/bw3aekw6.aspx
+enum SourceLanguage : uint8_t {
+ C = 0x00,
+ Cpp = 0x01,
+ Fortran = 0x02,
+ Masm = 0x03,
+ Pascal = 0x04,
+ Basic = 0x05,
+ Cobol = 0x06,
+ Link = 0x07,
+ Cvtres = 0x08,
+ Cvtpgd = 0x09,
+ CSharp = 0x0a,
+ VB = 0x0b,
+ ILAsm = 0x0c,
+ Java = 0x0d,
+ JScript = 0x0e,
+ MSIL = 0x0f,
+ HLSL = 0x10
+};
+
+/// These values correspond to the CV_call_e enumeration, and are documented
+/// at the following locations:
+/// https://msdn.microsoft.com/en-us/library/b2fc64ek.aspx
+/// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680207(v=vs.85).aspx
+///
enum class CallingConvention : uint8_t {
NearC = 0x00, // near right to left push, caller pops stack
FarC = 0x01, // far right to left push, caller pops stack
@@ -58,20 +204,7 @@ enum class ClassOptions : uint16_t {
Sealed = 0x0400,
Intrinsic = 0x2000
};
-
-inline ClassOptions operator|(ClassOptions a, ClassOptions b) {
- return static_cast<ClassOptions>(static_cast<uint16_t>(a) |
- static_cast<uint16_t>(b));
-}
-
-inline ClassOptions operator&(ClassOptions a, ClassOptions b) {
- return static_cast<ClassOptions>(static_cast<uint16_t>(a) &
- static_cast<uint16_t>(b));
-}
-
-inline ClassOptions operator~(ClassOptions a) {
- return static_cast<ClassOptions>(~static_cast<uint16_t>(a));
-}
+CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ClassOptions)
enum class FrameProcedureOptions : uint32_t {
None = 0x00000000,
@@ -95,22 +228,7 @@ enum class FrameProcedureOptions : uint32_t {
GuardCfg = 0x00200000,
GuardCfw = 0x00400000
};
-
-inline FrameProcedureOptions operator|(FrameProcedureOptions a,
- FrameProcedureOptions b) {
- return static_cast<FrameProcedureOptions>(static_cast<uint32_t>(a) |
- static_cast<uint32_t>(b));
-}
-
-inline FrameProcedureOptions operator&(FrameProcedureOptions a,
- FrameProcedureOptions b) {
- return static_cast<FrameProcedureOptions>(static_cast<uint32_t>(a) &
- static_cast<uint32_t>(b));
-}
-
-inline FrameProcedureOptions operator~(FrameProcedureOptions a) {
- return static_cast<FrameProcedureOptions>(~static_cast<uint32_t>(a));
-}
+CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(FrameProcedureOptions)
enum class FunctionOptions : uint8_t {
None = 0x00,
@@ -118,20 +236,7 @@ enum class FunctionOptions : uint8_t {
Constructor = 0x02,
ConstructorWithVirtualBases = 0x04
};
-
-inline FunctionOptions operator|(FunctionOptions a, FunctionOptions b) {
- return static_cast<FunctionOptions>(static_cast<uint8_t>(a) |
- static_cast<uint8_t>(b));
-}
-
-inline FunctionOptions operator&(FunctionOptions a, FunctionOptions b) {
- return static_cast<FunctionOptions>(static_cast<uint8_t>(a) &
- static_cast<uint8_t>(b));
-}
-
-inline FunctionOptions operator~(FunctionOptions a) {
- return static_cast<FunctionOptions>(~static_cast<uint8_t>(a));
-}
+CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(FunctionOptions)
enum class HfaKind : uint8_t {
None = 0x00,
@@ -140,6 +245,7 @@ enum class HfaKind : uint8_t {
Other = 0x03
};
+/// Source-level access specifier. (CV_access_e)
enum class MemberAccess : uint8_t {
None = 0,
Private = 1,
@@ -147,6 +253,7 @@ enum class MemberAccess : uint8_t {
Public = 3
};
+/// Part of member attribute flags. (CV_methodprop_e)
enum class MethodKind : uint8_t {
Vanilla = 0x00,
Virtual = 0x01,
@@ -157,49 +264,30 @@ enum class MethodKind : uint8_t {
PureIntroducingVirtual = 0x06
};
+/// Equivalent to CV_fldattr_t bitfield.
enum class MethodOptions : uint16_t {
None = 0x0000,
+ AccessMask = 0x0003,
+ MethodKindMask = 0x001c,
Pseudo = 0x0020,
+ NoInherit = 0x0040,
+ NoConstruct = 0x0080,
CompilerGenerated = 0x0100,
Sealed = 0x0200
};
+CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(MethodOptions)
-inline MethodOptions operator|(MethodOptions a, MethodOptions b) {
- return static_cast<MethodOptions>(static_cast<uint16_t>(a) |
- static_cast<uint16_t>(b));
-}
-
-inline MethodOptions operator&(MethodOptions a, MethodOptions b) {
- return static_cast<MethodOptions>(static_cast<uint16_t>(a) &
- static_cast<uint16_t>(b));
-}
-
-inline MethodOptions operator~(MethodOptions a) {
- return static_cast<MethodOptions>(~static_cast<uint16_t>(a));
-}
-
+/// Equivalent to CV_modifier_t.
enum class ModifierOptions : uint16_t {
None = 0x0000,
Const = 0x0001,
Volatile = 0x0002,
Unaligned = 0x0004
};
-
-inline ModifierOptions operator|(ModifierOptions a, ModifierOptions b) {
- return static_cast<ModifierOptions>(static_cast<uint16_t>(a) |
- static_cast<uint16_t>(b));
-}
-
-inline ModifierOptions operator&(ModifierOptions a, ModifierOptions b) {
- return static_cast<ModifierOptions>(static_cast<uint16_t>(a) &
- static_cast<uint16_t>(b));
-}
-
-inline ModifierOptions operator~(ModifierOptions a) {
- return static_cast<ModifierOptions>(~static_cast<uint16_t>(a));
-}
+CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ModifierOptions)
enum class ModuleSubstreamKind : uint32_t {
+ None = 0,
Symbols = 0xf1,
Lines = 0xf2,
StringTable = 0xf3,
@@ -207,9 +295,18 @@ enum class ModuleSubstreamKind : uint32_t {
FrameData = 0xf5,
InlineeLines = 0xf6,
CrossScopeImports = 0xf7,
- CrossScopeExports = 0xf8
+ CrossScopeExports = 0xf8,
+
+ // These appear to relate to .Net assembly info.
+ ILLines = 0xf9,
+ FuncMDTokenMap = 0xfa,
+ TypeMDTokenMap = 0xfb,
+ MergedAssemblyInput = 0xfc,
+
+ CoffSymbolRVA = 0xfd,
};
+/// Equivalent to CV_ptrtype_e.
enum class PointerKind : uint8_t {
Near16 = 0x00, // 16 bit pointer
Far16 = 0x01, // 16:16 far pointer
@@ -226,6 +323,7 @@ enum class PointerKind : uint8_t {
Near64 = 0x0c // 64 bit pointer
};
+/// Equivalent to CV_ptrmode_e.
enum class PointerMode : uint8_t {
Pointer = 0x00, // "normal" pointer
LValueReference = 0x01, // "old" reference
@@ -234,6 +332,7 @@ enum class PointerMode : uint8_t {
RValueReference = 0x04 // r-value reference
};
+/// Equivalent to misc lfPointerAttr bitfields.
enum class PointerOptions : uint32_t {
None = 0x00000000,
Flat32 = 0x00000100,
@@ -243,21 +342,9 @@ enum class PointerOptions : uint32_t {
Restrict = 0x00001000,
WinRTSmartPointer = 0x00080000
};
+CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(PointerOptions)
-inline PointerOptions operator|(PointerOptions a, PointerOptions b) {
- return static_cast<PointerOptions>(static_cast<uint16_t>(a) |
- static_cast<uint16_t>(b));
-}
-
-inline PointerOptions operator&(PointerOptions a, PointerOptions b) {
- return static_cast<PointerOptions>(static_cast<uint16_t>(a) &
- static_cast<uint16_t>(b));
-}
-
-inline PointerOptions operator~(PointerOptions a) {
- return static_cast<PointerOptions>(~static_cast<uint16_t>(a));
-}
-
+/// Equivalent to CV_pmtype_e.
enum class PointerToMemberRepresentation : uint16_t {
Unknown = 0x00, // not specified (pre VC8)
SingleInheritanceData = 0x01, // member data, single inheritance
@@ -270,82 +357,7 @@ enum class PointerToMemberRepresentation : uint16_t {
GeneralFunction = 0x08 // member function, most general
};
-enum class TypeRecordKind : uint16_t {
- None = 0,
-
- VirtualTableShape = 0x000a,
- Label = 0x000e,
- EndPrecompiledHeader = 0x0014,
-
- Modifier = 0x1001,
- Pointer = 0x1002,
- Procedure = 0x1008,
- MemberFunction = 0x1009,
-
- Oem = 0x100f,
- Oem2 = 0x1011,
-
- ArgumentList = 0x1201,
- FieldList = 0x1203,
- BitField = 0x1205,
- MethodList = 0x1206,
-
- BaseClass = 0x1400,
- VirtualBaseClass = 0x1401,
- IndirectVirtualBaseClass = 0x1402,
- Index = 0x1404,
- VirtualFunctionTablePointer = 0x1409,
-
- Enumerate = 0x1502,
- Array = 0x1503,
- Class = 0x1504,
- Structure = 0x1505,
- Union = 0x1506,
- Enum = 0x1507,
- Alias = 0x150a,
- Member = 0x150d,
- StaticMember = 0x150e,
- Method = 0x150f,
- NestedType = 0x1510,
- OneMethod = 0x1511,
- VirtualFunctionTable = 0x151d,
-
- FunctionId = 0x1601,
- MemberFunctionId = 0x1602,
- BuildInfo = 0x1603,
- SubstringList = 0x1604,
- StringId = 0x1605,
- UdtSourceLine = 0x1606,
-
- SByte = 0x8000,
- Int16 = 0x8001,
- UInt16 = 0x8002,
- Int32 = 0x8003,
- UInt32 = 0x8004,
- Single = 0x8005,
- Double = 0x8006,
- Float80 = 0x8007,
- Float128 = 0x8008,
- Int64 = 0x8009,
- UInt64 = 0x800a,
- Float48 = 0x800b,
- Complex32 = 0x800c,
- Complex64 = 0x800d,
- Complex80 = 0x800e,
- Complex128 = 0x800f,
- VarString = 0x8010,
-
- Int128 = 0x8017,
- UInt128 = 0x8018,
-
- Decimal = 0x8019,
- Date = 0x801a,
- Utf8String = 0x801b,
-
- Float16 = 0x801c
-};
-
-enum class VirtualTableSlotKind : uint8_t {
+enum class VFTableSlotKind : uint8_t {
Near16 = 0x00,
Far16 = 0x01,
This = 0x02,
@@ -361,6 +373,177 @@ enum class WindowsRTClassKind : uint8_t {
ValueClass = 0x02,
Interface = 0x03
};
+
+/// Corresponds to CV_LVARFLAGS bitfield.
+enum class LocalSymFlags : uint16_t {
+ None = 0,
+ IsParameter = 1 << 0,
+ IsAddressTaken = 1 << 1,
+ IsCompilerGenerated = 1 << 2,
+ IsAggregate = 1 << 3,
+ IsAggregated = 1 << 4,
+ IsAliased = 1 << 5,
+ IsAlias = 1 << 6,
+ IsReturnValue = 1 << 7,
+ IsOptimizedOut = 1 << 8,
+ IsEnregisteredGlobal = 1 << 9,
+ IsEnregisteredStatic = 1 << 10,
+};
+CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(LocalSymFlags)
+
+/// Corresponds to the CV_PROCFLAGS bitfield.
+enum class ProcSymFlags : uint8_t {
+ None = 0,
+ HasFP = 1 << 0,
+ HasIRET = 1 << 1,
+ HasFRET = 1 << 2,
+ IsNoReturn = 1 << 3,
+ IsUnreachable = 1 << 4,
+ HasCustomCallingConv = 1 << 5,
+ IsNoInline = 1 << 6,
+ HasOptimizedDebugInfo = 1 << 7,
+};
+CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ProcSymFlags)
+
+/// Corresponds to COMPILESYM2::Flags bitfield.
+enum class CompileSym2Flags : uint32_t {
+ EC = 1 << 8,
+ NoDbgInfo = 1 << 9,
+ LTCG = 1 << 10,
+ NoDataAlign = 1 << 11,
+ ManagedPresent = 1 << 12,
+ SecurityChecks = 1 << 13,
+ HotPatch = 1 << 14,
+ CVTCIL = 1 << 15,
+ MSILModule = 1 << 16,
+};
+CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(CompileSym2Flags)
+
+/// Corresponds to COMPILESYM3::Flags bitfield.
+enum class CompileSym3Flags : uint32_t {
+ EC = 1 << 8,
+ NoDbgInfo = 1 << 9,
+ LTCG = 1 << 10,
+ NoDataAlign = 1 << 11,
+ ManagedPresent = 1 << 12,
+ SecurityChecks = 1 << 13,
+ HotPatch = 1 << 14,
+ CVTCIL = 1 << 15,
+ MSILModule = 1 << 16,
+ Sdl = 1 << 17,
+ PGO = 1 << 18,
+ Exp = 1 << 19,
+};
+CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(CompileSym3Flags)
+
+enum class ExportFlags : uint16_t {
+ IsConstant = 1 << 0,
+ IsData = 1 << 1,
+ IsPrivate = 1 << 2,
+ HasNoName = 1 << 3,
+ HasExplicitOrdinal = 1 << 4,
+ IsForwarder = 1 << 5
+};
+CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ExportFlags)
+
+// Corresponds to BinaryAnnotationOpcode enum.
+enum class BinaryAnnotationsOpCode : uint32_t {
+ Invalid,
+ CodeOffset,
+ ChangeCodeOffsetBase,
+ ChangeCodeOffset,
+ ChangeCodeLength,
+ ChangeFile,
+ ChangeLineOffset,
+ ChangeLineEndDelta,
+ ChangeRangeKind,
+ ChangeColumnStart,
+ ChangeColumnEndDelta,
+ ChangeCodeOffsetAndLineOffset,
+ ChangeCodeLengthAndCodeOffset,
+ ChangeColumnEnd,
+};
+
+// Corresponds to CV_cookietype_e enum.
+enum class FrameCookieKind : uint8_t {
+ Copy,
+ XorStackPointer,
+ XorFramePointer,
+ XorR13,
+};
+
+// Corresponds to CV_HREG_e enum.
+enum class RegisterId : uint16_t {
+ Unknown = 0,
+ VFrame = 30006,
+ AL = 1,
+ CL = 2,
+ DL = 3,
+ BL = 4,
+ AH = 5,
+ CH = 6,
+ DH = 7,
+ BH = 8,
+ AX = 9,
+ CX = 10,
+ DX = 11,
+ BX = 12,
+ SP = 13,
+ BP = 14,
+ SI = 15,
+ DI = 16,
+ EAX = 17,
+ ECX = 18,
+ EDX = 19,
+ EBX = 20,
+ ESP = 21,
+ EBP = 22,
+ ESI = 23,
+ EDI = 24,
+ ES = 25,
+ CS = 26,
+ SS = 27,
+ DS = 28,
+ FS = 29,
+ GS = 30,
+ IP = 31,
+ RAX = 328,
+ RBX = 329,
+ RCX = 330,
+ RDX = 331,
+ RSI = 332,
+ RDI = 333,
+ RBP = 334,
+ RSP = 335,
+ R8 = 336,
+ R9 = 337,
+ R10 = 338,
+ R11 = 339,
+ R12 = 340,
+ R13 = 341,
+ R14 = 342,
+ R15 = 343,
+};
+
+/// These values correspond to the THUNK_ORDINAL enumeration.
+enum class ThunkOrdinal {
+ Standard,
+ ThisAdjustor,
+ Vcall,
+ Pcode,
+ UnknownLoad,
+ TrampIncremental,
+ BranchIsland
+};
+
+enum class TrampolineType { TrampIncremental, BranchIsland };
+
+// These values correspond to the CV_SourceChksum_t enumeration.
+enum class FileChecksumKind : uint8_t { None, MD5, SHA1, SHA256 };
+
+enum LineFlags : uint32_t {
+ HaveColumns = 1, // CV_LINES_HAVE_COLUMNS
+};
}
}
diff --git a/include/llvm/DebugInfo/CodeView/CodeViewError.h b/include/llvm/DebugInfo/CodeView/CodeViewError.h
new file mode 100644
index 0000000000000..69ff29aab6f11
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/CodeViewError.h
@@ -0,0 +1,44 @@
+//===- CodeViewError.h - Error extensions for CodeView ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_PDB_CODEVIEW_CODEVIEWERROR_H
+#define LLVM_DEBUGINFO_PDB_CODEVIEW_CODEVIEWERROR_H
+
+#include "llvm/Support/Error.h"
+
+#include <string>
+
+namespace llvm {
+namespace codeview {
+enum class cv_error_code {
+ unspecified = 1,
+ insufficient_buffer,
+ operation_unsupported,
+ corrupt_record,
+};
+
+/// Base class for errors originating when parsing raw PDB files
+class CodeViewError : public ErrorInfo<CodeViewError> {
+public:
+ static char ID;
+ CodeViewError(cv_error_code C);
+ CodeViewError(const std::string &Context);
+ CodeViewError(cv_error_code C, const std::string &Context);
+
+ void log(raw_ostream &OS) const override;
+ const std::string &getErrorMessage() const;
+ std::error_code convertToErrorCode() const override;
+
+private:
+ std::string ErrMsg;
+ cv_error_code Code;
+};
+}
+}
+#endif
diff --git a/include/llvm/DebugInfo/CodeView/EnumTables.h b/include/llvm/DebugInfo/CodeView/EnumTables.h
new file mode 100644
index 0000000000000..021288e576180
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/EnumTables.h
@@ -0,0 +1,42 @@
+//===- EnumTables.h Enum to string conversion tables ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_ENUMTABLES_H
+#define LLVM_DEBUGINFO_CODEVIEW_ENUMTABLES_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+#include <stdint.h>
+
+namespace llvm {
+namespace codeview {
+ArrayRef<EnumEntry<SymbolKind>> getSymbolTypeNames();
+ArrayRef<EnumEntry<uint16_t>> getRegisterNames();
+ArrayRef<EnumEntry<uint8_t>> getProcSymFlagNames();
+ArrayRef<EnumEntry<uint16_t>> getLocalFlagNames();
+ArrayRef<EnumEntry<uint8_t>> getFrameCookieKindNames();
+ArrayRef<EnumEntry<SourceLanguage>> getSourceLanguageNames();
+ArrayRef<EnumEntry<uint32_t>> getCompileSym2FlagNames();
+ArrayRef<EnumEntry<uint32_t>> getCompileSym3FlagNames();
+ArrayRef<EnumEntry<uint32_t>> getFileChecksumNames();
+ArrayRef<EnumEntry<unsigned>> getCPUTypeNames();
+ArrayRef<EnumEntry<uint32_t>> getFrameProcSymFlagNames();
+ArrayRef<EnumEntry<uint16_t>> getExportSymFlagNames();
+ArrayRef<EnumEntry<uint32_t>> getModuleSubstreamKindNames();
+ArrayRef<EnumEntry<uint8_t>> getThunkOrdinalNames();
+ArrayRef<EnumEntry<uint16_t>> getTrampolineNames();
+ArrayRef<EnumEntry<COFF::SectionCharacteristics>>
+getImageSectionCharacteristicNames();
+} // namespace codeview
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_ENUMTABLES_H
diff --git a/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h b/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h
index 1ed62487aeccc..75a075157d228 100644
--- a/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h
+++ b/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h
@@ -11,6 +11,7 @@
#define LLVM_DEBUGINFO_CODEVIEW_FIELDLISTRECORDBUILDER_H
#include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
namespace llvm {
namespace codeview {
@@ -46,31 +47,17 @@ private:
public:
FieldListRecordBuilder();
- void writeBaseClass(MemberAccess Access, TypeIndex Type, uint64_t Offset);
- void writeEnumerate(MemberAccess Access, uint64_t Value, StringRef Name);
- void writeIndirectVirtualBaseClass(MemberAccess Access, TypeIndex Type,
- TypeIndex VirtualBasePointerType,
- int64_t VirtualBasePointerOffset,
- uint64_t SlotIndex);
- void writeMember(MemberAccess Access, TypeIndex Type, uint64_t Offset,
- StringRef Name);
- void writeOneMethod(MemberAccess Access, MethodKind Kind,
- MethodOptions Options, TypeIndex Type,
- int32_t VTableSlotOffset, StringRef Name);
- void writeOneMethod(const MethodInfo &Method, StringRef Name);
- void writeMethod(uint16_t OverloadCount, TypeIndex MethodList,
- StringRef Name);
- void writeNestedType(TypeIndex Type, StringRef Name);
- void writeStaticMember(MemberAccess Access, TypeIndex Type, StringRef Name);
- void writeVirtualBaseClass(MemberAccess Access, TypeIndex Type,
- TypeIndex VirtualBasePointerType,
- int64_t VirtualBasePointerOffset,
- uint64_t SlotIndex);
- void writeVirtualBaseClass(TypeRecordKind Kind, MemberAccess Access,
- TypeIndex Type, TypeIndex VirtualBasePointerType,
- int64_t VirtualBasePointerOffset,
- uint64_t SlotIndex);
- void writeVirtualFunctionTablePointer(TypeIndex Type);
+ void reset() { ListRecordBuilder::reset(); }
+
+ void writeBaseClass(const BaseClassRecord &Record);
+ void writeEnumerator(const EnumeratorRecord &Record);
+ void writeDataMember(const DataMemberRecord &Record);
+ void writeOneMethod(const OneMethodRecord &Record);
+ void writeOverloadedMethod(const OverloadedMethodRecord &Record);
+ void writeNestedType(const NestedTypeRecord &Record);
+ void writeStaticDataMember(const StaticDataMemberRecord &Record);
+ void writeVirtualBaseClass(const VirtualBaseClassRecord &Record);
+ void writeVFPtr(const VFPtrRecord &Type);
};
}
}
diff --git a/include/llvm/DebugInfo/CodeView/Line.h b/include/llvm/DebugInfo/CodeView/Line.h
index a7cdbdaac32ff..975b503fe30b7 100644
--- a/include/llvm/DebugInfo/CodeView/Line.h
+++ b/include/llvm/DebugInfo/CodeView/Line.h
@@ -10,24 +10,32 @@
#ifndef LLVM_DEBUGINFO_CODEVIEW_LINE_H
#define LLVM_DEBUGINFO_CODEVIEW_LINE_H
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/Support/Endian.h"
#include <cinttypes>
namespace llvm {
namespace codeview {
+using llvm::support::ulittle32_t;
+
class LineInfo {
public:
- static const uint32_t AlwaysStepIntoLineNumber = 0xfeefee;
- static const uint32_t NeverStepIntoLineNumber = 0xf00f00;
+ enum : uint32_t {
+ AlwaysStepIntoLineNumber = 0xfeefee,
+ NeverStepIntoLineNumber = 0xf00f00
+ };
-private:
- static const uint32_t StartLineMask = 0x00ffffff;
- static const uint32_t EndLineDeltaMask = 0x7f000000;
- static const int EndLineDeltaShift = 24;
- static const uint32_t StatementFlag = 0x80000000u;
+ enum : int { EndLineDeltaShift = 24 };
+
+ enum : uint32_t {
+ StartLineMask = 0x00ffffff,
+ EndLineDeltaMask = 0x7f000000,
+ StatementFlag = 0x80000000u
+ };
-public:
LineInfo(uint32_t StartLine, uint32_t EndLine, bool IsStatement);
+ LineInfo(uint32_t LineData) : LineData(LineData) {}
uint32_t getStartLine() const { return LineData & StartLineMask; }
@@ -118,7 +126,29 @@ public:
bool isNeverStepInto() const { return LineInf.isNeverStepInto(); }
};
-}
-}
+
+enum class InlineeLinesSignature : uint32_t {
+ Normal, // CV_INLINEE_SOURCE_LINE_SIGNATURE
+ ExtraFiles // CV_INLINEE_SOURCE_LINE_SIGNATURE_EX
+};
+
+struct InlineeSourceLine {
+ TypeIndex Inlinee; // ID of the function that was inlined.
+ ulittle32_t FileID; // Offset into FileChecksums subsection.
+ ulittle32_t SourceLineNum; // First line of inlined code.
+ // If extra files present:
+ // ulittle32_t ExtraFileCount;
+ // ulittle32_t Files[];
+};
+
+struct FileChecksum {
+ ulittle32_t FileNameOffset; // Byte offset of filename in global string table.
+ uint8_t ChecksumSize; // Number of bytes of checksum.
+ uint8_t ChecksumKind; // FileChecksumKind
+ // Checksum bytes follow.
+};
+
+} // namespace codeview
+} // namespace llvm
#endif
diff --git a/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h b/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h
index df0a2e08a418b..00bf03d417a2c 100644
--- a/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h
+++ b/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h
@@ -14,6 +14,7 @@
namespace llvm {
namespace codeview {
+class TypeTableBuilder;
class ListRecordBuilder {
private:
@@ -28,14 +29,35 @@ protected:
public:
llvm::StringRef str() { return Builder.str(); }
+ void reset() {
+ Builder.reset(Kind);
+ ContinuationOffsets.clear();
+ SubrecordStart = 0;
+ }
+
+ void writeListContinuation(const ListContinuationRecord &R);
+
+ /// Writes this list record as a possible sequence of records.
+ TypeIndex writeListRecord(TypeTableBuilder &Table);
+
protected:
void finishSubRecord();
TypeRecordBuilder &getBuilder() { return Builder; }
private:
+ size_t getLastContinuationStart() const {
+ return ContinuationOffsets.empty() ? 0 : ContinuationOffsets.back();
+ }
+ size_t getLastContinuationEnd() const { return Builder.size(); }
+ size_t getLastContinuationSize() const {
+ return getLastContinuationEnd() - getLastContinuationStart();
+ }
+
+ TypeRecordKind Kind;
TypeRecordBuilder Builder;
SmallVector<size_t, 4> ContinuationOffsets;
+ size_t SubrecordStart = 0;
};
}
}
diff --git a/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h b/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h
index 5bfe2a0686722..002f885c7c5ae 100644
--- a/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h
+++ b/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h
@@ -10,12 +10,9 @@
#ifndef LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H
#define LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H
-#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-#include <functional>
-#include <memory>
-#include <unordered_map>
#include <vector>
namespace llvm {
@@ -23,46 +20,29 @@ namespace codeview {
class MemoryTypeTableBuilder : public TypeTableBuilder {
public:
- class Record {
- public:
- explicit Record(llvm::StringRef RData);
-
- const char *data() const { return Data.get(); }
- uint16_t size() const { return Size; }
-
- private:
- uint16_t Size;
- std::unique_ptr<char[]> Data;
- };
-
-private:
- class RecordHash : std::unary_function<llvm::StringRef, size_t> {
- public:
- size_t operator()(llvm::StringRef Val) const {
- return static_cast<size_t>(llvm::hash_value(Val));
- }
- };
-
-public:
MemoryTypeTableBuilder() {}
+ bool empty() const { return Records.empty(); }
+
template <typename TFunc> void ForEachRecord(TFunc Func) {
uint32_t Index = TypeIndex::FirstNonSimpleIndex;
- for (const std::unique_ptr<Record> &R : Records) {
- Func(TypeIndex(Index), R.get());
+ for (StringRef R : Records) {
+ Func(TypeIndex(Index), R);
++Index;
}
}
-private:
- virtual TypeIndex writeRecord(llvm::StringRef Data) override;
+protected:
+ TypeIndex writeRecord(llvm::StringRef Data) override;
private:
- std::vector<std::unique_ptr<Record>> Records;
- std::unordered_map<llvm::StringRef, TypeIndex, RecordHash> HashedRecords;
+ std::vector<StringRef> Records;
+ BumpPtrAllocator RecordStorage;
+ DenseMap<StringRef, TypeIndex> HashedRecords;
};
-}
-}
-#endif
+} // end namespace codeview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H
diff --git a/include/llvm/DebugInfo/CodeView/ModuleSubstream.h b/include/llvm/DebugInfo/CodeView/ModuleSubstream.h
new file mode 100644
index 0000000000000..6affac801d4dc
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/ModuleSubstream.h
@@ -0,0 +1,87 @@
+//===- ModuleSubstream.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H
+#define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/StreamArray.h"
+#include "llvm/DebugInfo/CodeView/StreamRef.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace codeview {
+
+// Corresponds to the `CV_DebugSSubsectionHeader_t` structure.
+struct ModuleSubsectionHeader {
+ support::ulittle32_t Kind; // codeview::ModuleSubstreamKind enum
+ support::ulittle32_t Length; // number of bytes occupied by this record.
+};
+
+// Corresponds to the `CV_DebugSLinesHeader_t` structure.
+struct LineSubstreamHeader {
+ support::ulittle32_t RelocOffset; // Code offset of line contribution.
+ support::ulittle16_t RelocSegment; // Code segment of line contribution.
+ support::ulittle16_t Flags; // See LineFlags enumeration.
+ support::ulittle32_t CodeSize; // Code size of this line contribution.
+};
+
+// Corresponds to the `CV_DebugSLinesFileBlockHeader_t` structure.
+struct LineFileBlockHeader {
+ support::ulittle32_t NameIndex; // Index in DBI name buffer of filename.
+ support::ulittle32_t NumLines; // Number of lines
+ support::ulittle32_t BlockSize; // Code size of block, in bytes.
+ // The following two variable length arrays appear immediately after the
+ // header. The structure definitions follow.
+ // LineNumberEntry Lines[NumLines];
+ // ColumnNumberEntry Columns[NumLines];
+};
+
+// Corresponds to `CV_Line_t` structure
+struct LineNumberEntry {
+ support::ulittle32_t Offset; // Offset to start of code bytes for line number
+ support::ulittle32_t Flags; // Start:24, End:7, IsStatement:1
+};
+
+// Corresponds to `CV_Column_t` structure
+struct ColumnNumberEntry {
+ support::ulittle16_t StartColumn;
+ support::ulittle16_t EndColumn;
+};
+
+class ModuleSubstream {
+public:
+ ModuleSubstream();
+ ModuleSubstream(ModuleSubstreamKind Kind, StreamRef Data);
+ static Error initialize(StreamRef Stream, ModuleSubstream &Info);
+ uint32_t getRecordLength() const;
+ ModuleSubstreamKind getSubstreamKind() const;
+ StreamRef getRecordData() const;
+
+private:
+ ModuleSubstreamKind Kind;
+ StreamRef Data;
+};
+
+template <> struct VarStreamArrayExtractor<ModuleSubstream> {
+ Error operator()(StreamRef Stream, uint32_t &Length,
+ ModuleSubstream &Info) const {
+ if (auto EC = ModuleSubstream::initialize(Stream, Info))
+ return EC;
+ Length = Info.getRecordLength();
+ return Error::success();
+ }
+};
+
+typedef VarStreamArray<ModuleSubstream> ModuleSubstreamArray;
+}
+}
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H
diff --git a/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h b/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h
new file mode 100644
index 0000000000000..6df2309037122
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h
@@ -0,0 +1,121 @@
+//===- ModuleSubstreamVisitor.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H
+#define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/Line.h"
+#include "llvm/DebugInfo/CodeView/ModuleSubstream.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/CodeView/StreamRef.h"
+
+namespace llvm {
+namespace codeview {
+
+struct LineColumnEntry {
+ support::ulittle32_t NameIndex;
+ FixedStreamArray<LineNumberEntry> LineNumbers;
+ FixedStreamArray<ColumnNumberEntry> Columns;
+};
+
+template <> class VarStreamArrayExtractor<LineColumnEntry> {
+public:
+ VarStreamArrayExtractor(const LineSubstreamHeader *Header) : Header(Header) {}
+
+ Error operator()(StreamRef Stream, uint32_t &Len,
+ LineColumnEntry &Item) const {
+ const LineFileBlockHeader *BlockHeader;
+ StreamReader Reader(Stream);
+ if (auto EC = Reader.readObject(BlockHeader))
+ return EC;
+ bool HasColumn = Header->Flags & LineFlags::HaveColumns;
+ uint32_t LineInfoSize =
+ BlockHeader->NumLines *
+ (sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0));
+ if (BlockHeader->BlockSize < sizeof(LineFileBlockHeader))
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Invalid line block record size");
+ uint32_t Size = BlockHeader->BlockSize - sizeof(LineFileBlockHeader);
+ if (LineInfoSize > Size)
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Invalid line block record size");
+ // The value recorded in BlockHeader->BlockSize includes the size of
+ // LineFileBlockHeader.
+ Len = BlockHeader->BlockSize;
+ Item.NameIndex = BlockHeader->NameIndex;
+ if (auto EC = Reader.readArray(Item.LineNumbers, BlockHeader->NumLines))
+ return EC;
+ if (HasColumn) {
+ if (auto EC = Reader.readArray(Item.Columns, BlockHeader->NumLines))
+ return EC;
+ }
+ return Error::success();
+ }
+
+private:
+ const LineSubstreamHeader *Header;
+};
+
+struct FileChecksumEntry {
+ uint32_t FileNameOffset; // Byte offset of filename in global stringtable.
+ FileChecksumKind Kind; // The type of checksum.
+ ArrayRef<uint8_t> Checksum; // The bytes of the checksum.
+};
+
+template <> class VarStreamArrayExtractor<FileChecksumEntry> {
+public:
+ Error operator()(StreamRef Stream, uint32_t &Len,
+ FileChecksumEntry &Item) const {
+ const FileChecksum *Header;
+ StreamReader Reader(Stream);
+ if (auto EC = Reader.readObject(Header))
+ return EC;
+ Item.FileNameOffset = Header->FileNameOffset;
+ Item.Kind = static_cast<FileChecksumKind>(Header->ChecksumKind);
+ if (auto EC = Reader.readBytes(Item.Checksum, Header->ChecksumSize))
+ return EC;
+ Len = sizeof(FileChecksum) + Header->ChecksumSize;
+ return Error::success();
+ }
+};
+
+typedef VarStreamArray<LineColumnEntry> LineInfoArray;
+typedef VarStreamArray<FileChecksumEntry> FileChecksumArray;
+
+class IModuleSubstreamVisitor {
+public:
+ virtual ~IModuleSubstreamVisitor() {}
+
+ virtual Error visitUnknown(ModuleSubstreamKind Kind, StreamRef Data) = 0;
+ virtual Error visitSymbols(StreamRef Data);
+ virtual Error visitLines(StreamRef Data, const LineSubstreamHeader *Header,
+ const LineInfoArray &Lines);
+ virtual Error visitStringTable(StreamRef Data);
+ virtual Error visitFileChecksums(StreamRef Data,
+ const FileChecksumArray &Checksums);
+ virtual Error visitFrameData(StreamRef Data);
+ virtual Error visitInlineeLines(StreamRef Data);
+ virtual Error visitCrossScopeImports(StreamRef Data);
+ virtual Error visitCrossScopeExports(StreamRef Data);
+ virtual Error visitILLines(StreamRef Data);
+ virtual Error visitFuncMDTokenMap(StreamRef Data);
+ virtual Error visitTypeMDTokenMap(StreamRef Data);
+ virtual Error visitMergedAssemblyInput(StreamRef Data);
+ virtual Error visitCoffSymbolRVA(StreamRef Data);
+};
+
+Error visitModuleSubstream(const ModuleSubstream &R,
+ IModuleSubstreamVisitor &V);
+
+} // namespace codeview
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H
diff --git a/include/llvm/DebugInfo/CodeView/RecordSerialization.h b/include/llvm/DebugInfo/CodeView/RecordSerialization.h
new file mode 100644
index 0000000000000..84179f5f81f74
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/RecordSerialization.h
@@ -0,0 +1,278 @@
+//===- RecordSerialization.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_RECORDSERIALIZATION_H
+#define LLVM_DEBUGINFO_CODEVIEW_RECORDSERIALIZATION_H
+
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include <cinttypes>
+#include <tuple>
+
+namespace llvm {
+namespace codeview {
+using llvm::support::little32_t;
+using llvm::support::ulittle16_t;
+using llvm::support::ulittle32_t;
+
+struct RecordPrefix {
+ ulittle16_t RecordLen; // Record length, starting from &Leaf.
+ ulittle16_t RecordKind; // Record kind enum (SymRecordKind or TypeRecordKind)
+};
+
+/// Reinterpret a byte array as an array of characters. Does not interpret as
+/// a C string, as StringRef has several helpers (split) that make that easy.
+StringRef getBytesAsCharacters(ArrayRef<uint8_t> LeafData);
+StringRef getBytesAsCString(ArrayRef<uint8_t> LeafData);
+
+/// Consumes sizeof(T) bytes from the given byte sequence. Returns an error if
+/// there are not enough bytes remaining. Reinterprets the consumed bytes as a
+/// T object and points 'Res' at them.
+template <typename T, typename U>
+inline std::error_code consumeObject(U &Data, const T *&Res) {
+ if (Data.size() < sizeof(*Res))
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Res = reinterpret_cast<const T *>(Data.data());
+ Data = Data.drop_front(sizeof(*Res));
+ return std::error_code();
+}
+
+inline std::error_code consume(ArrayRef<uint8_t> &Data) {
+ return std::error_code();
+}
+
+/// Decodes a numeric "leaf" value. These are integer literals encountered in
+/// the type stream. If the value is positive and less than LF_NUMERIC (1 <<
+/// 15), it is emitted directly in Data. Otherwise, it has a tag like LF_CHAR
+/// that indicates the bitwidth and sign of the numeric data.
+std::error_code consume(ArrayRef<uint8_t> &Data, APSInt &Num);
+std::error_code consume(StringRef &Data, APSInt &Num);
+
+/// Decodes a numeric leaf value that is known to be a particular type.
+std::error_code consume_numeric(ArrayRef<uint8_t> &Data, uint64_t &Value);
+
+/// Decodes signed and unsigned fixed-length integers.
+std::error_code consume(ArrayRef<uint8_t> &Data, uint32_t &Item);
+std::error_code consume(StringRef &Data, uint32_t &Item);
+std::error_code consume(ArrayRef<uint8_t> &Data, int32_t &Item);
+
+/// Decodes a null terminated string.
+std::error_code consume(ArrayRef<uint8_t> &Data, StringRef &Item);
+
+/// Decodes an arbitrary object whose layout matches that of the underlying
+/// byte sequence, and returns a pointer to the object.
+template <typename T>
+std::error_code consume(ArrayRef<uint8_t> &Data, T *&Item) {
+ return consumeObject(Data, Item);
+}
+
+template <typename T, typename U> struct serialize_conditional_impl {
+ serialize_conditional_impl(T &Item, U Func) : Item(Item), Func(Func) {}
+
+ std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
+ if (!Func())
+ return std::error_code();
+ return consume(Data, Item);
+ }
+
+ T &Item;
+ U Func;
+};
+
+template <typename T, typename U>
+serialize_conditional_impl<T, U> serialize_conditional(T &Item, U Func) {
+ return serialize_conditional_impl<T, U>(Item, Func);
+}
+
+template <typename T, typename U> struct serialize_array_impl {
+ serialize_array_impl(ArrayRef<T> &Item, U Func) : Item(Item), Func(Func) {}
+
+ std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
+ uint32_t N = Func();
+ if (N == 0)
+ return std::error_code();
+
+ uint32_t Size = sizeof(T) * N;
+
+ if (Size / sizeof(T) != N)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ if (Data.size() < Size)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ Item = ArrayRef<T>(reinterpret_cast<const T *>(Data.data()), N);
+ Data = Data.drop_front(Size);
+ return std::error_code();
+ }
+
+ ArrayRef<T> &Item;
+ U Func;
+};
+
+template <typename T> struct serialize_vector_tail_impl {
+ serialize_vector_tail_impl(std::vector<T> &Item) : Item(Item) {}
+
+ std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
+ T Field;
+ // Stop when we run out of bytes or we hit record padding bytes.
+ while (!Data.empty() && Data.front() < LF_PAD0) {
+ if (auto EC = consume(Data, Field))
+ return EC;
+ Item.push_back(Field);
+ }
+ return std::error_code();
+ }
+
+ std::vector<T> &Item;
+};
+
+struct serialize_null_term_string_array_impl {
+ serialize_null_term_string_array_impl(std::vector<StringRef> &Item)
+ : Item(Item) {}
+
+ std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
+ if (Data.empty())
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ StringRef Field;
+ // Stop when we run out of bytes or we hit record padding bytes.
+ while (Data.front() != 0) {
+ if (auto EC = consume(Data, Field))
+ return EC;
+ Item.push_back(Field);
+ if (Data.empty())
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ }
+ Data = Data.drop_front(1);
+ return std::error_code();
+ }
+
+ std::vector<StringRef> &Item;
+};
+
+template <typename T> struct serialize_arrayref_tail_impl {
+ serialize_arrayref_tail_impl(ArrayRef<T> &Item) : Item(Item) {}
+
+ std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
+ uint32_t Count = Data.size() / sizeof(T);
+ Item = ArrayRef<T>(reinterpret_cast<const T *>(Data.begin()), Count);
+ return std::error_code();
+ }
+
+ ArrayRef<T> &Item;
+};
+
+template <typename T> struct serialize_numeric_impl {
+ serialize_numeric_impl(T &Item) : Item(Item) {}
+
+ std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
+ return consume_numeric(Data, Item);
+ }
+
+ T &Item;
+};
+
+template <typename T, typename U>
+serialize_array_impl<T, U> serialize_array(ArrayRef<T> &Item, U Func) {
+ return serialize_array_impl<T, U>(Item, Func);
+}
+
+inline serialize_null_term_string_array_impl
+serialize_null_term_string_array(std::vector<StringRef> &Item) {
+ return serialize_null_term_string_array_impl(Item);
+}
+
+template <typename T>
+serialize_vector_tail_impl<T> serialize_array_tail(std::vector<T> &Item) {
+ return serialize_vector_tail_impl<T>(Item);
+}
+
+template <typename T>
+serialize_arrayref_tail_impl<T> serialize_array_tail(ArrayRef<T> &Item) {
+ return serialize_arrayref_tail_impl<T>(Item);
+}
+
+template <typename T> serialize_numeric_impl<T> serialize_numeric(T &Item) {
+ return serialize_numeric_impl<T>(Item);
+}
+
+// This field is only present in the byte record if the condition is true. The
+// condition is evaluated lazily, so it can depend on items that were
+// deserialized
+// earlier.
+#define CV_CONDITIONAL_FIELD(I, C) \
+ serialize_conditional(I, [&]() { return !!(C); })
+
+// This is an array of N items, where N is evaluated lazily, so it can refer
+// to a field deserialized earlier.
+#define CV_ARRAY_FIELD_N(I, N) serialize_array(I, [&]() { return N; })
+
+// This is an array that exhausts the remainder of the input buffer.
+#define CV_ARRAY_FIELD_TAIL(I) serialize_array_tail(I)
+
+// This is an array that consumes null terminated strings until a double null
+// is encountered.
+#define CV_STRING_ARRAY_NULL_TERM(I) serialize_null_term_string_array(I)
+
+#define CV_NUMERIC_FIELD(I) serialize_numeric(I)
+
+template <typename T, typename U>
+std::error_code consume(ArrayRef<uint8_t> &Data,
+ const serialize_conditional_impl<T, U> &Item) {
+ return Item.deserialize(Data);
+}
+
+template <typename T, typename U>
+std::error_code consume(ArrayRef<uint8_t> &Data,
+ const serialize_array_impl<T, U> &Item) {
+ return Item.deserialize(Data);
+}
+
+inline std::error_code
+consume(ArrayRef<uint8_t> &Data,
+ const serialize_null_term_string_array_impl &Item) {
+ return Item.deserialize(Data);
+}
+
+template <typename T>
+std::error_code consume(ArrayRef<uint8_t> &Data,
+ const serialize_vector_tail_impl<T> &Item) {
+ return Item.deserialize(Data);
+}
+
+template <typename T>
+std::error_code consume(ArrayRef<uint8_t> &Data,
+ const serialize_arrayref_tail_impl<T> &Item) {
+ return Item.deserialize(Data);
+}
+
+template <typename T>
+std::error_code consume(ArrayRef<uint8_t> &Data,
+ const serialize_numeric_impl<T> &Item) {
+ return Item.deserialize(Data);
+}
+
+template <typename T, typename U, typename... Args>
+std::error_code consume(ArrayRef<uint8_t> &Data, T &&X, U &&Y,
+ Args &&... Rest) {
+ if (auto EC = consume(Data, X))
+ return EC;
+ return consume(Data, Y, std::forward<Args>(Rest)...);
+}
+
+#define CV_DESERIALIZE(...) \
+ if (auto EC = consume(__VA_ARGS__)) \
+ return EC;
+}
+}
+
+#endif
diff --git a/include/llvm/DebugInfo/CodeView/StreamArray.h b/include/llvm/DebugInfo/CodeView/StreamArray.h
new file mode 100644
index 0000000000000..0b9349aac7538
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/StreamArray.h
@@ -0,0 +1,275 @@
+//===- StreamArray.h - Array backed by an arbitrary stream ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H
+#define LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H
+
+#include "llvm/DebugInfo/CodeView/StreamRef.h"
+#include "llvm/Support/Error.h"
+
+#include <functional>
+#include <type_traits>
+
+namespace llvm {
+namespace codeview {
+
+/// VarStreamArrayExtractor is intended to be specialized to provide customized
+/// extraction logic. On input it receives a StreamRef pointing to the
+/// beginning of the next record, but where the length of the record is not yet
+/// known. Upon completion, it should return an appropriate Error instance if
+/// a record could not be extracted, or if one could be extracted it should
+/// return success and set Len to the number of bytes this record occupied in
+/// the underlying stream, and it should fill out the fields of the value type
+/// Item appropriately to represent the current record.
+///
+/// You can specialize this template for your own custom value types to avoid
+/// having to specify a second template argument to VarStreamArray (documented
+/// below).
+template <typename T> struct VarStreamArrayExtractor {
+ // Method intentionally deleted. You must provide an explicit specialization
+ // with the following method implemented.
+ Error operator()(StreamRef Stream, uint32_t &Len, T &Item) const = delete;
+};
+
+/// VarStreamArray represents an array of variable length records backed by a
+/// stream. This could be a contiguous sequence of bytes in memory, it could
+/// be a file on disk, or it could be a PDB stream where bytes are stored as
+/// discontiguous blocks in a file. Usually it is desirable to treat arrays
+/// as contiguous blocks of memory, but doing so with large PDB files, for
+/// example, could mean allocating huge amounts of memory just to allow
+/// re-ordering of stream data to be contiguous before iterating over it. By
+/// abstracting this out, we need not duplicate this memory, and we can
+/// iterate over arrays in arbitrarily formatted streams. Elements are parsed
+/// lazily on iteration, so there is no upfront cost associated with building
+/// a VarStreamArray, no matter how large it may be.
+///
+/// You create a VarStreamArray by specifying a ValueType and an Extractor type.
+/// If you do not specify an Extractor type, it expects you to specialize
+/// VarStreamArrayExtractor<T> for your ValueType.
+///
+/// By default an Extractor is default constructed in the class, but in some
+/// cases you might find it useful for an Extractor to maintain state across
+/// extractions. In this case you can provide your own Extractor through a
+/// secondary constructor. The following examples show various ways of
+/// creating a VarStreamArray.
+///
+/// // Will use VarStreamArrayExtractor<MyType> as the extractor.
+/// VarStreamArray<MyType> MyTypeArray;
+///
+/// // Will use a default-constructed MyExtractor as the extractor.
+/// VarStreamArray<MyType, MyExtractor> MyTypeArray2;
+///
+/// // Will use the specific instance of MyExtractor provided.
+/// // MyExtractor need not be default-constructible in this case.
+/// MyExtractor E(SomeContext);
+/// VarStreamArray<MyType, MyExtractor> MyTypeArray3(E);
+///
+template <typename ValueType, typename Extractor> class VarStreamArrayIterator;
+
+template <typename ValueType,
+ typename Extractor = VarStreamArrayExtractor<ValueType>>
+class VarStreamArray {
+ friend class VarStreamArrayIterator<ValueType, Extractor>;
+
+public:
+ typedef VarStreamArrayIterator<ValueType, Extractor> Iterator;
+
+ VarStreamArray() {}
+ explicit VarStreamArray(const Extractor &E) : E(E) {}
+
+ explicit VarStreamArray(StreamRef Stream) : Stream(Stream) {}
+ VarStreamArray(StreamRef Stream, const Extractor &E) : Stream(Stream), E(E) {}
+
+ VarStreamArray(const VarStreamArray<ValueType, Extractor> &Other)
+ : Stream(Other.Stream), E(Other.E) {}
+
+ Iterator begin(bool *HadError = nullptr) const {
+ return Iterator(*this, E, HadError);
+ }
+
+ Iterator end() const { return Iterator(E); }
+
+ const Extractor &getExtractor() const { return E; }
+
+ StreamRef getUnderlyingStream() const { return Stream; }
+
+private:
+ StreamRef Stream;
+ Extractor E;
+};
+
+template <typename ValueType, typename Extractor> class VarStreamArrayIterator {
+ typedef VarStreamArrayIterator<ValueType, Extractor> IterType;
+ typedef VarStreamArray<ValueType, Extractor> ArrayType;
+
+public:
+ VarStreamArrayIterator(const ArrayType &Array, const Extractor &E,
+ bool *HadError = nullptr)
+ : IterRef(Array.Stream), Array(&Array), HadError(HadError), Extract(E) {
+ if (IterRef.getLength() == 0)
+ moveToEnd();
+ else {
+ auto EC = Extract(IterRef, ThisLen, ThisValue);
+ if (EC) {
+ consumeError(std::move(EC));
+ markError();
+ }
+ }
+ }
+ VarStreamArrayIterator() {}
+ explicit VarStreamArrayIterator(const Extractor &E) : Extract(E) {}
+ ~VarStreamArrayIterator() {}
+
+ bool operator==(const IterType &R) const {
+ if (Array && R.Array) {
+ // Both have a valid array, make sure they're same.
+ assert(Array == R.Array);
+ return IterRef == R.IterRef;
+ }
+
+ // Both iterators are at the end.
+ if (!Array && !R.Array)
+ return true;
+
+ // One is not at the end and one is.
+ return false;
+ }
+
+ bool operator!=(const IterType &R) { return !(*this == R); }
+
+ const ValueType &operator*() const {
+ assert(Array && !HasError);
+ return ThisValue;
+ }
+
+ IterType &operator++() {
+ // We are done with the current record, discard it so that we are
+ // positioned at the next record.
+ IterRef = IterRef.drop_front(ThisLen);
+ if (IterRef.getLength() == 0) {
+ // There is nothing after the current record, we must make this an end
+ // iterator.
+ moveToEnd();
+ } else {
+ // There is some data after the current record.
+ auto EC = Extract(IterRef, ThisLen, ThisValue);
+ if (EC) {
+ consumeError(std::move(EC));
+ markError();
+ } else if (ThisLen == 0) {
+ // An empty record? Make this an end iterator.
+ moveToEnd();
+ }
+ }
+ return *this;
+ }
+
+ IterType operator++(int) {
+ IterType Original = *this;
+ ++*this;
+ return Original;
+ }
+
+private:
+ void moveToEnd() {
+ Array = nullptr;
+ ThisLen = 0;
+ }
+ void markError() {
+ moveToEnd();
+ HasError = true;
+ if (HadError != nullptr)
+ *HadError = true;
+ }
+
+ ValueType ThisValue;
+ StreamRef IterRef;
+ const ArrayType *Array{nullptr};
+ uint32_t ThisLen{0};
+ bool HasError{false};
+ bool *HadError{nullptr};
+ Extractor Extract;
+};
+
+template <typename T> class FixedStreamArrayIterator;
+
+template <typename T> class FixedStreamArray {
+ friend class FixedStreamArrayIterator<T>;
+
+public:
+ FixedStreamArray() : Stream() {}
+ FixedStreamArray(StreamRef Stream) : Stream(Stream) {
+ assert(Stream.getLength() % sizeof(T) == 0);
+ }
+
+ const T &operator[](uint32_t Index) const {
+ assert(Index < size());
+ uint32_t Off = Index * sizeof(T);
+ ArrayRef<uint8_t> Data;
+ if (auto EC = Stream.readBytes(Off, sizeof(T), Data)) {
+ assert(false && "Unexpected failure reading from stream");
+ // This should never happen since we asserted that the stream length was
+ // an exact multiple of the element size.
+ consumeError(std::move(EC));
+ }
+ return *reinterpret_cast<const T *>(Data.data());
+ }
+
+ uint32_t size() const { return Stream.getLength() / sizeof(T); }
+
+ FixedStreamArrayIterator<T> begin() const {
+ return FixedStreamArrayIterator<T>(*this, 0);
+ }
+ FixedStreamArrayIterator<T> end() const {
+ return FixedStreamArrayIterator<T>(*this, size());
+ }
+
+ StreamRef getUnderlyingStream() const { return Stream; }
+
+private:
+ StreamRef Stream;
+};
+
+template <typename T> class FixedStreamArrayIterator {
+public:
+ FixedStreamArrayIterator(const FixedStreamArray<T> &Array, uint32_t Index)
+ : Array(Array), Index(Index) {}
+
+ bool operator==(const FixedStreamArrayIterator<T> &R) {
+ assert(&Array == &R.Array);
+ return Index == R.Index;
+ }
+
+ bool operator!=(const FixedStreamArrayIterator<T> &R) {
+ return !(*this == R);
+ }
+
+ const T &operator*() const { return Array[Index]; }
+
+ FixedStreamArrayIterator<T> &operator++() {
+ assert(Index < Array.size());
+ ++Index;
+ return *this;
+ }
+
+ FixedStreamArrayIterator<T> operator++(int) {
+ FixedStreamArrayIterator<T> Original = *this;
+ ++*this;
+ return Original;
+ }
+
+private:
+ const FixedStreamArray<T> &Array;
+ uint32_t Index;
+};
+
+} // namespace codeview
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H
diff --git a/include/llvm/DebugInfo/CodeView/StreamInterface.h b/include/llvm/DebugInfo/CodeView/StreamInterface.h
new file mode 100644
index 0000000000000..241aec4578700
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/StreamInterface.h
@@ -0,0 +1,55 @@
+//===- StreamInterface.h - Base interface for a stream of data --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMINTERFACE_H
+#define LLVM_DEBUGINFO_CODEVIEW_STREAMINTERFACE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+
+namespace llvm {
+namespace codeview {
+
+/// StreamInterface abstracts the notion of a data stream. This way, an
+/// implementation could implement trivial reading from a contiguous memory
+/// buffer or, as in the case of PDB files, reading from a set of possibly
+/// discontiguous blocks. The implementation is required to return references
+/// to stable memory, so if this is not possible (for example in the case of
+/// a PDB file with discontiguous blocks, it must keep its own pool of temp
+/// storage.
+class StreamInterface {
+public:
+ virtual ~StreamInterface() {}
+
+ // Given an offset into the stream and a number of bytes, attempt to read
+ // the bytes and set the output ArrayRef to point to a reference into the
+ // stream, without copying any data.
+ virtual Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) const = 0;
+
+ // Given an offset into the stream, read as much as possible without copying
+ // any data.
+ virtual Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) const = 0;
+
+ // Attempt to write the given bytes into the stream at the desired offset.
+ // This will always necessitate a copy. Cannot shrink or grow the stream,
+ // only writes into existing allocated space.
+ virtual Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const = 0;
+
+ virtual uint32_t getLength() const = 0;
+
+ virtual Error commit() const = 0;
+};
+
+} // end namespace codeview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMINTERFACE_H
diff --git a/include/llvm/DebugInfo/CodeView/StreamReader.h b/include/llvm/DebugInfo/CodeView/StreamReader.h
new file mode 100644
index 0000000000000..2f497c2c43f14
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/StreamReader.h
@@ -0,0 +1,111 @@
+//===- StreamReader.h - Reads bytes and objects from a stream ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H
+#define LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/StreamArray.h"
+#include "llvm/DebugInfo/CodeView/StreamInterface.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+
+#include <string>
+
+namespace llvm {
+namespace codeview {
+
+class StreamRef;
+
+class StreamReader {
+public:
+ StreamReader(StreamRef Stream);
+
+ Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer);
+ Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size);
+ Error readInteger(uint16_t &Dest);
+ Error readInteger(uint32_t &Dest);
+ Error readZeroString(StringRef &Dest);
+ Error readFixedString(StringRef &Dest, uint32_t Length);
+ Error readStreamRef(StreamRef &Ref);
+ Error readStreamRef(StreamRef &Ref, uint32_t Length);
+
+ template <typename T> Error readEnum(T &Dest) {
+ typename std::underlying_type<T>::type N;
+ if (auto EC = readInteger(N))
+ return EC;
+ Dest = static_cast<T>(N);
+ return Error::success();
+ }
+
+ template <typename T> Error readObject(const T *&Dest) {
+ ArrayRef<uint8_t> Buffer;
+ if (auto EC = readBytes(Buffer, sizeof(T)))
+ return EC;
+ Dest = reinterpret_cast<const T *>(Buffer.data());
+ return Error::success();
+ }
+
+ template <typename T>
+ Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
+ ArrayRef<uint8_t> Bytes;
+ if (NumElements == 0) {
+ Array = ArrayRef<T>();
+ return Error::success();
+ }
+
+ if (NumElements > UINT32_MAX/sizeof(T))
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+
+ if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
+ return EC;
+ Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
+ return Error::success();
+ }
+
+ template <typename T, typename U>
+ Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) {
+ StreamRef S;
+ if (auto EC = readStreamRef(S, Size))
+ return EC;
+ Array = VarStreamArray<T, U>(S, Array.getExtractor());
+ return Error::success();
+ }
+
+ template <typename T>
+ Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) {
+ if (NumItems == 0) {
+ Array = FixedStreamArray<T>();
+ return Error::success();
+ }
+ uint32_t Length = NumItems * sizeof(T);
+ if (Length / sizeof(T) != NumItems)
+ return make_error<CodeViewError>(cv_error_code::corrupt_record);
+ if (Offset + Length > Stream.getLength())
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ StreamRef View = Stream.slice(Offset, Length);
+ Array = FixedStreamArray<T>(View);
+ Offset += Length;
+ return Error::success();
+ }
+
+ void setOffset(uint32_t Off) { Offset = Off; }
+ uint32_t getOffset() const { return Offset; }
+ uint32_t getLength() const { return Stream.getLength(); }
+ uint32_t bytesRemaining() const { return getLength() - getOffset(); }
+
+private:
+ StreamRef Stream;
+ uint32_t Offset;
+};
+} // namespace codeview
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H
diff --git a/include/llvm/DebugInfo/CodeView/StreamRef.h b/include/llvm/DebugInfo/CodeView/StreamRef.h
new file mode 100644
index 0000000000000..a4f244a322899
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/StreamRef.h
@@ -0,0 +1,104 @@
+//===- StreamRef.h - A copyable reference to a stream -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMREF_H
+#define LLVM_DEBUGINFO_CODEVIEW_STREAMREF_H
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/StreamInterface.h"
+
+namespace llvm {
+namespace codeview {
+
+class StreamRef {
+public:
+ StreamRef() : Stream(nullptr), ViewOffset(0), Length(0) {}
+ StreamRef(const StreamInterface &Stream)
+ : Stream(&Stream), ViewOffset(0), Length(Stream.getLength()) {}
+ StreamRef(const StreamInterface &Stream, uint32_t Offset, uint32_t Length)
+ : Stream(&Stream), ViewOffset(Offset), Length(Length) {}
+
+ // Use StreamRef.slice() instead.
+ StreamRef(const StreamRef &S, uint32_t Offset, uint32_t Length) = delete;
+
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) const {
+ if (ViewOffset + Offset < Offset)
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ if (Size + Offset > Length)
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ return Stream->readBytes(ViewOffset + Offset, Size, Buffer);
+ }
+
+ // Given an offset into the stream, read as much as possible without copying
+ // any data.
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) const {
+ if (Offset >= Length)
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+
+ if (auto EC = Stream->readLongestContiguousChunk(Offset, Buffer))
+ return EC;
+ // This StreamRef might refer to a smaller window over a larger stream. In
+ // that case we will have read out more bytes than we should return, because
+ // we should not read past the end of the current view.
+ uint32_t MaxLength = Length - Offset;
+ if (Buffer.size() > MaxLength)
+ Buffer = Buffer.slice(0, MaxLength);
+ return Error::success();
+ }
+
+ Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const {
+ if (Data.size() + Offset > Length)
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ return Stream->writeBytes(ViewOffset + Offset, Data);
+ }
+
+ uint32_t getLength() const { return Length; }
+
+ Error commit() const { return Stream->commit(); }
+
+ StreamRef drop_front(uint32_t N) const {
+ if (!Stream)
+ return StreamRef();
+
+ N = std::min(N, Length);
+ return StreamRef(*Stream, ViewOffset + N, Length - N);
+ }
+
+ StreamRef keep_front(uint32_t N) const {
+ if (!Stream)
+ return StreamRef();
+ N = std::min(N, Length);
+ return StreamRef(*Stream, ViewOffset, N);
+ }
+
+ StreamRef slice(uint32_t Offset, uint32_t Len) const {
+ return drop_front(Offset).keep_front(Len);
+ }
+
+ bool operator==(const StreamRef &Other) const {
+ if (Stream != Other.Stream)
+ return false;
+ if (ViewOffset != Other.ViewOffset)
+ return false;
+ if (Length != Other.Length)
+ return false;
+ return true;
+ }
+
+private:
+ const StreamInterface *Stream;
+ uint32_t ViewOffset;
+ uint32_t Length;
+};
+}
+}
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMREF_H
diff --git a/include/llvm/DebugInfo/CodeView/StreamWriter.h b/include/llvm/DebugInfo/CodeView/StreamWriter.h
new file mode 100644
index 0000000000000..4d393d2ef7905
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/StreamWriter.h
@@ -0,0 +1,86 @@
+//===- StreamWriter.h - Writes bytes and objects to a stream ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMWRITER_H
+#define LLVM_DEBUGINFO_CODEVIEW_STREAMWRITER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/StreamArray.h"
+#include "llvm/DebugInfo/CodeView/StreamInterface.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+
+#include <string>
+
+namespace llvm {
+namespace codeview {
+
+class StreamRef;
+
+class StreamWriter {
+public:
+ StreamWriter(StreamRef Stream);
+
+ Error writeBytes(ArrayRef<uint8_t> Buffer);
+ Error writeInteger(uint16_t Dest);
+ Error writeInteger(uint32_t Dest);
+ Error writeZeroString(StringRef Str);
+ Error writeFixedString(StringRef Str);
+ Error writeStreamRef(StreamRef Ref);
+ Error writeStreamRef(StreamRef Ref, uint32_t Size);
+
+ template <typename T> Error writeEnum(T Num) {
+ return writeInteger(
+ static_cast<typename std::underlying_type<T>::type>(Num));
+ }
+
+ template <typename T> Error writeObject(const T &Obj) {
+ static_assert(!std::is_pointer<T>::value,
+ "writeObject should not be used with pointers, to write "
+ "the pointed-to value dereference the pointer before calling "
+ "writeObject");
+ return writeBytes(
+ ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&Obj), sizeof(T)));
+ }
+
+ template <typename T> Error writeArray(ArrayRef<T> Array) {
+ if (Array.size() == 0)
+ return Error::success();
+
+ if (Array.size() > UINT32_MAX / sizeof(T))
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+
+ return writeBytes(
+ ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Array.data()),
+ Array.size() * sizeof(T)));
+ }
+
+ template <typename T, typename U>
+ Error writeArray(VarStreamArray<T, U> Array) {
+ return writeStreamRef(Array.getUnderlyingStream());
+ }
+
+ template <typename T> Error writeArray(FixedStreamArray<T> Array) {
+ return writeStreamRef(Array.getUnderlyingStream());
+ }
+
+ void setOffset(uint32_t Off) { Offset = Off; }
+ uint32_t getOffset() const { return Offset; }
+ uint32_t getLength() const { return Stream.getLength(); }
+ uint32_t bytesRemaining() const { return getLength() - getOffset(); }
+
+private:
+ StreamRef Stream;
+ uint32_t Offset;
+};
+} // namespace codeview
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H
diff --git a/include/llvm/DebugInfo/CodeView/SymbolDumpDelegate.h b/include/llvm/DebugInfo/CodeView/SymbolDumpDelegate.h
new file mode 100644
index 0000000000000..30b0a40451cb8
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/SymbolDumpDelegate.h
@@ -0,0 +1,37 @@
+//===-- SymbolDumpDelegate.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPDELEGATE_H
+#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPDELEGATE_H
+
+#include "SymbolVisitorDelegate.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <stdint.h>
+
+namespace llvm {
+
+namespace codeview {
+
+class SymbolDumpDelegate : public SymbolVisitorDelegate {
+public:
+ virtual ~SymbolDumpDelegate() {}
+
+ virtual void printRelocatedField(StringRef Label, uint32_t RelocOffset,
+ uint32_t Offset,
+ StringRef *RelocSym = nullptr) = 0;
+ virtual void printBinaryBlockWithRelocs(StringRef Label,
+ ArrayRef<uint8_t> Block) = 0;
+};
+} // end namespace codeview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPDELEGATE_H
diff --git a/include/llvm/DebugInfo/CodeView/SymbolDumper.h b/include/llvm/DebugInfo/CodeView/SymbolDumper.h
new file mode 100644
index 0000000000000..648e40f55810b
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/SymbolDumper.h
@@ -0,0 +1,54 @@
+//===-- SymbolDumper.h - CodeView symbol info dumper ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPER_H
+#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+
+namespace llvm {
+class ScopedPrinter;
+
+namespace codeview {
+class CVTypeDumper;
+
+/// Dumper for CodeView symbol streams found in COFF object files and PDB files.
+class CVSymbolDumper {
+public:
+ CVSymbolDumper(ScopedPrinter &W, CVTypeDumper &CVTD,
+ std::unique_ptr<SymbolDumpDelegate> ObjDelegate,
+ bool PrintRecordBytes)
+ : W(W), CVTD(CVTD), ObjDelegate(std::move(ObjDelegate)),
+ PrintRecordBytes(PrintRecordBytes) {}
+
+ /// Dumps one type record. Returns false if there was a type parsing error,
+ /// and true otherwise. This should be called in order, since the dumper
+ /// maintains state about previous records which are necessary for cross
+ /// type references.
+ bool dump(const CVRecord<SymbolKind> &Record);
+
+ /// Dumps the type records in Data. Returns false if there was a type stream
+ /// parse error, and true otherwise.
+ bool dump(const CVSymbolArray &Symbols);
+
+private:
+ ScopedPrinter &W;
+ CVTypeDumper &CVTD;
+ std::unique_ptr<SymbolDumpDelegate> ObjDelegate;
+
+ bool PrintRecordBytes;
+};
+} // end namespace codeview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPER_H
diff --git a/include/llvm/DebugInfo/CodeView/SymbolRecord.h b/include/llvm/DebugInfo/CodeView/SymbolRecord.h
new file mode 100644
index 0000000000000..77e894fba4a9b
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/SymbolRecord.h
@@ -0,0 +1,1452 @@
+//===- SymbolRecord.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H
+#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H
+
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+#include "llvm/DebugInfo/CodeView/StreamArray.h"
+#include "llvm/DebugInfo/CodeView/StreamInterface.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace codeview {
+
+using llvm::support::ulittle16_t;
+using llvm::support::ulittle32_t;
+using llvm::support::little32_t;
+
+class SymbolRecord {
+protected:
+ explicit SymbolRecord(SymbolRecordKind Kind) : Kind(Kind) {}
+
+public:
+ SymbolRecordKind getKind() const { return Kind; }
+
+private:
+ SymbolRecordKind Kind;
+};
+
+// S_GPROC32, S_LPROC32, S_GPROC32_ID, S_LPROC32_ID, S_LPROC32_DPC or
+// S_LPROC32_DPC_ID
+class ProcSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t PtrParent;
+ ulittle32_t PtrEnd;
+ ulittle32_t PtrNext;
+ ulittle32_t CodeSize;
+ ulittle32_t DbgStart;
+ ulittle32_t DbgEnd;
+ TypeIndex FunctionType;
+ ulittle32_t CodeOffset;
+ ulittle16_t Segment;
+ uint8_t Flags; // ProcSymFlags enum
+ // Name: The null-terminated name follows.
+ };
+
+ ProcSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H,
+ StringRef Name)
+ : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H), Name(Name) {
+ }
+
+ static ErrorOr<ProcSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return ProcSym(Kind, RecordOffset, H, Name);
+ }
+
+ uint32_t getRelocationOffset() const {
+ return RecordOffset + offsetof(Hdr, CodeOffset);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+// S_THUNK32
+class Thunk32Sym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t Parent;
+ ulittle32_t End;
+ ulittle32_t Next;
+ ulittle32_t Off;
+ ulittle16_t Seg;
+ ulittle16_t Len;
+ uint8_t Ord; // ThunkOrdinal enumeration
+ // Name: The null-terminated name follows.
+ // Variant portion of thunk
+ };
+
+ Thunk32Sym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H,
+ StringRef Name, ArrayRef<uint8_t> VariantData)
+ : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H), Name(Name),
+ VariantData(VariantData) {}
+
+ static ErrorOr<Thunk32Sym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ ArrayRef<uint8_t> VariantData;
+
+ CV_DESERIALIZE(Data, H, Name, CV_ARRAY_FIELD_TAIL(VariantData));
+
+ return Thunk32Sym(Kind, RecordOffset, H, Name, VariantData);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+ ArrayRef<uint8_t> VariantData;
+};
+
+// S_TRAMPOLINE
+class TrampolineSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle16_t Type; // TrampolineType enum
+ ulittle16_t Size;
+ ulittle32_t ThunkOff;
+ ulittle32_t TargetOff;
+ ulittle16_t ThunkSection;
+ ulittle16_t TargetSection;
+ };
+
+ TrampolineSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H)
+ : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H) {}
+
+ static ErrorOr<TrampolineSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+
+ CV_DESERIALIZE(Data, H);
+
+ return TrampolineSym(Kind, RecordOffset, H);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+};
+
+// S_SECTION
+class SectionSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle16_t SectionNumber;
+ uint8_t Alignment;
+ uint8_t Reserved; // Must be 0
+ ulittle32_t Rva;
+ ulittle32_t Length;
+ ulittle32_t Characteristics;
+ // Name: The null-terminated name follows.
+ };
+
+ SectionSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H,
+ StringRef Name)
+ : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H), Name(Name) {
+ }
+
+ static ErrorOr<SectionSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+
+ CV_DESERIALIZE(Data, H, Name);
+
+ return SectionSym(Kind, RecordOffset, H, Name);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+// S_COFFGROUP
+class CoffGroupSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t Size;
+ ulittle32_t Characteristics;
+ ulittle32_t Offset;
+ ulittle16_t Segment;
+ // Name: The null-terminated name follows.
+ };
+
+ CoffGroupSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H,
+ StringRef Name)
+ : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H), Name(Name) {
+ }
+
+ static ErrorOr<CoffGroupSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+
+ CV_DESERIALIZE(Data, H, Name);
+
+ return CoffGroupSym(Kind, RecordOffset, H, Name);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+class ScopeEndSym : public SymbolRecord {
+public:
+ ScopeEndSym(SymbolRecordKind Kind, uint32_t RecordOffset)
+ : SymbolRecord(Kind), RecordOffset(RecordOffset) {}
+
+ static ErrorOr<ScopeEndSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ return ScopeEndSym(Kind, RecordOffset);
+ }
+ uint32_t RecordOffset;
+};
+
+class CallerSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t Count;
+ };
+
+ CallerSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *Header,
+ ArrayRef<TypeIndex> Indices)
+ : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*Header),
+ Indices(Indices) {}
+
+ static ErrorOr<CallerSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *Header;
+ ArrayRef<TypeIndex> Indices;
+
+ CV_DESERIALIZE(Data, Header, CV_ARRAY_FIELD_N(Indices, Header->Count));
+
+ return CallerSym(Kind, RecordOffset, Header, Indices);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ ArrayRef<TypeIndex> Indices;
+};
+
+struct BinaryAnnotationIterator {
+ struct AnnotationData {
+ BinaryAnnotationsOpCode OpCode;
+ StringRef Name;
+ uint32_t U1;
+ uint32_t U2;
+ int32_t S1;
+ };
+
+ BinaryAnnotationIterator(ArrayRef<uint8_t> Annotations) : Data(Annotations) {}
+ BinaryAnnotationIterator() {}
+ BinaryAnnotationIterator(const BinaryAnnotationIterator &Other)
+ : Data(Other.Data) {}
+
+ bool operator==(BinaryAnnotationIterator Other) const {
+ return Data == Other.Data;
+ }
+
+ bool operator!=(BinaryAnnotationIterator Other) const {
+ return !(*this == Other);
+ }
+
+ 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;
+ }
+
+ BinaryAnnotationIterator operator++(int) {
+ BinaryAnnotationIterator Orig(*this);
+ ++(*this);
+ return Orig;
+ }
+
+ const AnnotationData &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);
+ AnnotationData 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;
+ }
+ }
+ Current = Result;
+ return true;
+ }
+
+ Optional<AnnotationData> Current;
+ ArrayRef<uint8_t> Data;
+ ArrayRef<uint8_t> Next;
+};
+
+// S_INLINESITE
+class InlineSiteSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t PtrParent;
+ ulittle32_t PtrEnd;
+ TypeIndex Inlinee;
+ // BinaryAnnotations
+ };
+
+ InlineSiteSym(uint32_t RecordOffset, const Hdr *H,
+ ArrayRef<uint8_t> Annotations)
+ : SymbolRecord(SymbolRecordKind::InlineSiteSym),
+ RecordOffset(RecordOffset), Header(*H), Annotations(Annotations) {}
+
+ static ErrorOr<InlineSiteSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ ArrayRef<uint8_t> Annotations;
+ CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Annotations));
+
+ return InlineSiteSym(RecordOffset, H, Annotations);
+ }
+
+ llvm::iterator_range<BinaryAnnotationIterator> annotations() const {
+ return llvm::make_range(BinaryAnnotationIterator(Annotations),
+ BinaryAnnotationIterator());
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+
+private:
+ ArrayRef<uint8_t> Annotations;
+};
+
+// S_PUB32
+class PublicSym32 : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t Index; // Type index, or Metadata token if a managed symbol
+ ulittle32_t Off;
+ ulittle16_t Seg;
+ // Name: The null-terminated name follows.
+ };
+
+ PublicSym32(uint32_t RecordOffset, const Hdr *H, StringRef Name)
+ : SymbolRecord(SymbolRecordKind::PublicSym32), RecordOffset(RecordOffset),
+ Header(*H), Name(Name) {}
+
+ static ErrorOr<PublicSym32> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return PublicSym32(RecordOffset, H, Name);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+// S_REGISTER
+class RegisterSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t Index; // Type index or Metadata token
+ ulittle16_t Register; // RegisterId enumeration
+ // Name: The null-terminated name follows.
+ };
+
+ RegisterSym(uint32_t RecordOffset, const Hdr *H, StringRef Name)
+ : SymbolRecord(SymbolRecordKind::RegisterSym), RecordOffset(RecordOffset),
+ Header(*H), Name(Name) {}
+
+ static ErrorOr<RegisterSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return RegisterSym(RecordOffset, H, Name);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+// S_PROCREF, S_LPROCREF
+class ProcRefSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t SumName; // SUC of the name (?)
+ ulittle32_t SymOffset; // Offset of actual symbol in $$Symbols
+ ulittle16_t Mod; // Module containing the actual symbol
+ // Name: The null-terminated name follows.
+ };
+
+ ProcRefSym(uint32_t RecordOffset, const Hdr *H, StringRef Name)
+ : SymbolRecord(SymbolRecordKind::ProcRefSym), RecordOffset(RecordOffset),
+ Header(*H), Name(Name) {}
+
+ static ErrorOr<ProcRefSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return ProcRefSym(RecordOffset, H, Name);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+// S_LOCAL
+class LocalSym : public SymbolRecord {
+public:
+ struct Hdr {
+ TypeIndex Type;
+ ulittle16_t Flags; // LocalSymFlags enum
+ // Name: The null-terminated name follows.
+ };
+
+ LocalSym(uint32_t RecordOffset, const Hdr *H, StringRef Name)
+ : SymbolRecord(SymbolRecordKind::LocalSym), RecordOffset(RecordOffset),
+ Header(*H), Name(Name) {}
+
+ static ErrorOr<LocalSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return LocalSym(RecordOffset, H, Name);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+struct LocalVariableAddrRange {
+ ulittle32_t OffsetStart;
+ ulittle16_t ISectStart;
+ ulittle16_t Range;
+};
+
+struct LocalVariableAddrGap {
+ ulittle16_t GapStartOffset;
+ ulittle16_t Range;
+};
+
+enum : uint16_t { MaxDefRange = 0xf000 };
+
+// S_DEFRANGE
+class DefRangeSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t Program;
+ LocalVariableAddrRange Range;
+ // LocalVariableAddrGap Gaps[];
+ };
+
+ DefRangeSym(uint32_t RecordOffset, const Hdr *H,
+ ArrayRef<LocalVariableAddrGap> Gaps)
+ : SymbolRecord(SymbolRecordKind::DefRangeSym), RecordOffset(RecordOffset),
+ Header(*H), Gaps(Gaps) {}
+
+ static ErrorOr<DefRangeSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ ArrayRef<LocalVariableAddrGap> Gaps;
+ CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps));
+
+ return DefRangeSym(RecordOffset, H, Gaps);
+ }
+
+ uint32_t getRelocationOffset() const {
+ return RecordOffset + offsetof(Hdr, Range);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ ArrayRef<LocalVariableAddrGap> Gaps;
+};
+
+// S_DEFRANGE_SUBFIELD
+class DefRangeSubfieldSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t Program;
+ ulittle16_t OffsetInParent;
+ LocalVariableAddrRange Range;
+ // LocalVariableAddrGap Gaps[];
+ };
+ DefRangeSubfieldSym(uint32_t RecordOffset, const Hdr *H,
+ ArrayRef<LocalVariableAddrGap> Gaps)
+ : SymbolRecord(SymbolRecordKind::DefRangeSubfieldSym),
+ RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {}
+
+ static ErrorOr<DefRangeSubfieldSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ ArrayRef<LocalVariableAddrGap> Gaps;
+ CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps));
+
+ return DefRangeSubfieldSym(RecordOffset, H, Gaps);
+ }
+
+ uint32_t getRelocationOffset() const {
+ return RecordOffset + offsetof(Hdr, Range);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ ArrayRef<LocalVariableAddrGap> Gaps;
+};
+
+// S_DEFRANGE_REGISTER
+class DefRangeRegisterSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle16_t Register;
+ ulittle16_t MayHaveNoName;
+ LocalVariableAddrRange Range;
+ // LocalVariableAddrGap Gaps[];
+ };
+
+ DefRangeRegisterSym(uint32_t RecordOffset, const Hdr *H,
+ ArrayRef<LocalVariableAddrGap> Gaps)
+ : SymbolRecord(SymbolRecordKind::DefRangeRegisterSym),
+ RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {}
+
+ DefRangeRegisterSym(uint16_t Register, uint16_t MayHaveNoName,
+ uint32_t OffsetStart, uint16_t ISectStart, uint16_t Range,
+ ArrayRef<LocalVariableAddrGap> Gaps)
+ : SymbolRecord(SymbolRecordKind::DefRangeRegisterSym), RecordOffset(0),
+ Gaps(Gaps) {
+ Header.Register = Register;
+ Header.MayHaveNoName = MayHaveNoName;
+ Header.Range.OffsetStart = OffsetStart;
+ Header.Range.ISectStart = ISectStart;
+ Header.Range.Range = Range;
+ }
+
+ static ErrorOr<DefRangeRegisterSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ ArrayRef<LocalVariableAddrGap> Gaps;
+ CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps));
+
+ return DefRangeRegisterSym(RecordOffset, H, Gaps);
+ }
+
+ uint32_t getRelocationOffset() const {
+ return RecordOffset + offsetof(Hdr, Range);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ ArrayRef<LocalVariableAddrGap> Gaps;
+};
+
+// S_DEFRANGE_SUBFIELD_REGISTER
+class DefRangeSubfieldRegisterSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle16_t Register; // Register to which the variable is relative
+ ulittle16_t MayHaveNoName;
+ ulittle32_t OffsetInParent;
+ LocalVariableAddrRange Range;
+ // LocalVariableAddrGap Gaps[];
+ };
+
+ DefRangeSubfieldRegisterSym(uint32_t RecordOffset, const Hdr *H,
+ ArrayRef<LocalVariableAddrGap> Gaps)
+ : SymbolRecord(SymbolRecordKind::DefRangeSubfieldRegisterSym),
+ RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {}
+
+ DefRangeSubfieldRegisterSym(uint16_t Register, uint16_t MayHaveNoName,
+ uint32_t OffsetInParent,
+ ArrayRef<LocalVariableAddrGap> Gaps)
+ : SymbolRecord(SymbolRecordKind::DefRangeSubfieldRegisterSym),
+ RecordOffset(0), Gaps(Gaps) {
+ Header.Register = Register;
+ Header.MayHaveNoName = MayHaveNoName;
+ Header.OffsetInParent = OffsetInParent;
+ }
+
+ static ErrorOr<DefRangeSubfieldRegisterSym>
+ deserialize(SymbolRecordKind Kind, uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ ArrayRef<LocalVariableAddrGap> Gaps;
+ CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps));
+
+ return DefRangeSubfieldRegisterSym(RecordOffset, H, Gaps);
+ }
+
+ uint32_t getRelocationOffset() const {
+ return RecordOffset + offsetof(Hdr, Range);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ ArrayRef<LocalVariableAddrGap> Gaps;
+};
+
+// S_DEFRANGE_FRAMEPOINTER_REL
+class DefRangeFramePointerRelSym : public SymbolRecord {
+public:
+ struct Hdr {
+ little32_t Offset; // Offset from the frame pointer register
+ LocalVariableAddrRange Range;
+ // LocalVariableAddrGap Gaps[];
+ };
+
+ DefRangeFramePointerRelSym(uint32_t RecordOffset, const Hdr *H,
+ ArrayRef<LocalVariableAddrGap> Gaps)
+ : SymbolRecord(SymbolRecordKind::DefRangeFramePointerRelSym),
+ RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {}
+
+ static ErrorOr<DefRangeFramePointerRelSym>
+ deserialize(SymbolRecordKind Kind, uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ ArrayRef<LocalVariableAddrGap> Gaps;
+ CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps));
+
+ return DefRangeFramePointerRelSym(RecordOffset, H, Gaps);
+ }
+
+ uint32_t getRelocationOffset() const {
+ return RecordOffset + offsetof(Hdr, Range);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ ArrayRef<LocalVariableAddrGap> Gaps;
+};
+
+// S_DEFRANGE_REGISTER_REL
+class DefRangeRegisterRelSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle16_t BaseRegister;
+ ulittle16_t Flags;
+ little32_t BasePointerOffset;
+ LocalVariableAddrRange Range;
+ // LocalVariableAddrGap Gaps[];
+ };
+
+ DefRangeRegisterRelSym(uint32_t RecordOffset, const Hdr *H,
+ ArrayRef<LocalVariableAddrGap> Gaps)
+ : SymbolRecord(SymbolRecordKind::DefRangeRegisterRelSym),
+ RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {}
+
+ DefRangeRegisterRelSym(uint16_t BaseRegister, uint16_t Flags,
+ int32_t BasePointerOffset, uint32_t OffsetStart,
+ uint16_t ISectStart, uint16_t Range,
+ ArrayRef<LocalVariableAddrGap> Gaps)
+ : SymbolRecord(SymbolRecordKind::DefRangeRegisterRelSym), RecordOffset(0),
+ Gaps(Gaps) {
+ Header.BaseRegister = BaseRegister;
+ Header.Flags = Flags;
+ Header.BasePointerOffset = BasePointerOffset;
+ Header.Range.OffsetStart = OffsetStart;
+ Header.Range.ISectStart = ISectStart;
+ Header.Range.Range = Range;
+ }
+
+ static ErrorOr<DefRangeRegisterRelSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ ArrayRef<LocalVariableAddrGap> Gaps;
+ CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps));
+
+ return DefRangeRegisterRelSym(RecordOffset, H, Gaps);
+ }
+
+ bool hasSpilledUDTMember() const { return Header.Flags & 1; }
+ uint16_t offsetInParent() const { return Header.Flags >> 4; }
+
+ uint32_t getRelocationOffset() const {
+ return RecordOffset + offsetof(Hdr, Range);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ ArrayRef<LocalVariableAddrGap> Gaps;
+};
+
+// S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE
+class DefRangeFramePointerRelFullScopeSym : public SymbolRecord {
+public:
+ struct Hdr {
+ little32_t Offset; // Offset from the frame pointer register
+ };
+
+ DefRangeFramePointerRelFullScopeSym(uint32_t RecordOffset, const Hdr *H)
+ : SymbolRecord(SymbolRecordKind::DefRangeFramePointerRelFullScopeSym),
+ RecordOffset(RecordOffset), Header(*H) {}
+
+ static ErrorOr<DefRangeFramePointerRelFullScopeSym>
+ deserialize(SymbolRecordKind Kind, uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ CV_DESERIALIZE(Data, H);
+
+ return DefRangeFramePointerRelFullScopeSym(RecordOffset, H);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+};
+
+// S_BLOCK32
+class BlockSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t PtrParent;
+ ulittle32_t PtrEnd;
+ ulittle32_t CodeSize;
+ ulittle32_t CodeOffset;
+ ulittle16_t Segment;
+ // Name: The null-terminated name follows.
+ };
+
+ BlockSym(uint32_t RecordOffset, const Hdr *H, StringRef Name)
+ : SymbolRecord(SymbolRecordKind::BlockSym), RecordOffset(RecordOffset),
+ Header(*H), Name(Name) {}
+
+ static ErrorOr<BlockSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return BlockSym(RecordOffset, H, Name);
+ }
+
+ uint32_t getRelocationOffset() const {
+ return RecordOffset + offsetof(Hdr, CodeOffset);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+// S_LABEL32
+class LabelSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t CodeOffset;
+ ulittle16_t Segment;
+ uint8_t Flags; // CV_PROCFLAGS
+ // Name: The null-terminated name follows.
+ };
+
+ LabelSym(uint32_t RecordOffset, const Hdr *H, StringRef Name)
+ : SymbolRecord(SymbolRecordKind::LabelSym), RecordOffset(RecordOffset),
+ Header(*H), Name(Name) {}
+
+ static ErrorOr<LabelSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return LabelSym(RecordOffset, H, Name);
+ }
+
+ uint32_t getRelocationOffset() const {
+ return RecordOffset + offsetof(Hdr, CodeOffset);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+// S_OBJNAME
+class ObjNameSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t Signature;
+ // Name: The null-terminated name follows.
+ };
+
+ ObjNameSym(uint32_t RecordOffset, const Hdr *H, StringRef Name)
+ : SymbolRecord(SymbolRecordKind::ObjNameSym), RecordOffset(RecordOffset),
+ Header(*H), Name(Name) {}
+
+ static ErrorOr<ObjNameSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return ObjNameSym(RecordOffset, H, Name);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+// S_ENVBLOCK
+class EnvBlockSym : public SymbolRecord {
+public:
+ struct Hdr {
+ uint8_t Reserved;
+ // Sequence of zero terminated strings.
+ };
+
+ EnvBlockSym(uint32_t RecordOffset, const Hdr *H,
+ const std::vector<StringRef> &Fields)
+ : SymbolRecord(SymbolRecordKind::EnvBlockSym), RecordOffset(RecordOffset),
+ Header(*H), Fields(Fields) {}
+
+ static ErrorOr<EnvBlockSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ std::vector<StringRef> Fields;
+ CV_DESERIALIZE(Data, H, CV_STRING_ARRAY_NULL_TERM(Fields));
+
+ return EnvBlockSym(RecordOffset, H, Fields);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ std::vector<StringRef> Fields;
+};
+
+// S_EXPORT
+class ExportSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle16_t Ordinal;
+ ulittle16_t Flags; // ExportFlags
+ // Name: The null-terminated name follows.
+ };
+
+ ExportSym(uint32_t RecordOffset, const Hdr *H, StringRef Name)
+ : SymbolRecord(SymbolRecordKind::ExportSym), RecordOffset(RecordOffset),
+ Header(*H), Name(Name) {}
+
+ static ErrorOr<ExportSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return ExportSym(RecordOffset, H, Name);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+// S_FILESTATIC
+class FileStaticSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t Index; // Type Index
+ ulittle32_t ModFilenameOffset; // Index of mod filename in string table
+ ulittle16_t Flags; // LocalSymFlags enum
+ // Name: The null-terminated name follows.
+ };
+
+ FileStaticSym(uint32_t RecordOffset, const Hdr *H, StringRef Name)
+ : SymbolRecord(SymbolRecordKind::FileStaticSym),
+ RecordOffset(RecordOffset), Header(*H), Name(Name) {}
+
+ static ErrorOr<FileStaticSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return FileStaticSym(RecordOffset, H, Name);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+// S_COMPILE2
+class Compile2Sym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t flags; // CompileSym2Flags enum
+ uint8_t getLanguage() const { return flags & 0xFF; }
+ unsigned short Machine; // CPUType enum
+ unsigned short VersionFrontendMajor;
+ unsigned short VersionFrontendMinor;
+ unsigned short VersionFrontendBuild;
+ unsigned short VersionBackendMajor;
+ unsigned short VersionBackendMinor;
+ unsigned short VersionBackendBuild;
+ // Version: The null-terminated version string follows.
+ // Optional block of zero terminated strings terminated with a double zero.
+ };
+
+ Compile2Sym(uint32_t RecordOffset, const Hdr *H, StringRef Version)
+ : SymbolRecord(SymbolRecordKind::Compile2Sym), RecordOffset(RecordOffset),
+ Header(*H), Version(Version) {}
+
+ static ErrorOr<Compile2Sym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Version;
+ CV_DESERIALIZE(Data, H, Version);
+
+ return Compile2Sym(RecordOffset, H, Version);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Version;
+};
+
+// S_COMPILE3
+class Compile3Sym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t flags; // CompileSym3Flags enum
+ uint8_t getLanguage() const { return flags & 0xff; }
+ ulittle16_t Machine; // CPUType enum
+ ulittle16_t VersionFrontendMajor;
+ ulittle16_t VersionFrontendMinor;
+ ulittle16_t VersionFrontendBuild;
+ ulittle16_t VersionFrontendQFE;
+ ulittle16_t VersionBackendMajor;
+ ulittle16_t VersionBackendMinor;
+ ulittle16_t VersionBackendBuild;
+ ulittle16_t VersionBackendQFE;
+ // VersionString: The null-terminated version string follows.
+ };
+
+ Compile3Sym(uint32_t RecordOffset, const Hdr *H, StringRef Version)
+ : SymbolRecord(SymbolRecordKind::Compile3Sym), RecordOffset(RecordOffset),
+ Header(*H), Version(Version) {}
+
+ static ErrorOr<Compile3Sym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Version;
+ CV_DESERIALIZE(Data, H, Version);
+
+ return Compile3Sym(RecordOffset, H, Version);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Version;
+};
+
+// S_FRAMEPROC
+class FrameProcSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t TotalFrameBytes;
+ ulittle32_t PaddingFrameBytes;
+ ulittle32_t OffsetToPadding;
+ ulittle32_t BytesOfCalleeSavedRegisters;
+ ulittle32_t OffsetOfExceptionHandler;
+ ulittle16_t SectionIdOfExceptionHandler;
+ ulittle32_t Flags;
+ };
+
+ FrameProcSym(uint32_t RecordOffset, const Hdr *H)
+ : SymbolRecord(SymbolRecordKind::FrameProcSym),
+ RecordOffset(RecordOffset), Header(*H) {}
+
+ static ErrorOr<FrameProcSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ CV_DESERIALIZE(Data, H);
+
+ return FrameProcSym(RecordOffset, H);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+};
+
+// S_CALLSITEINFO
+class CallSiteInfoSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t CodeOffset;
+ ulittle16_t Segment;
+ ulittle16_t Reserved;
+ TypeIndex Type;
+ };
+
+ CallSiteInfoSym(uint32_t RecordOffset, const Hdr *H)
+ : SymbolRecord(SymbolRecordKind::CallSiteInfoSym),
+ RecordOffset(RecordOffset), Header(*H) {}
+
+ static ErrorOr<CallSiteInfoSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ CV_DESERIALIZE(Data, H);
+
+ return CallSiteInfoSym(RecordOffset, H);
+ }
+
+ uint32_t getRelocationOffset() const {
+ return RecordOffset + offsetof(Hdr, CodeOffset);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+};
+
+// S_HEAPALLOCSITE
+class HeapAllocationSiteSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t CodeOffset;
+ ulittle16_t Segment;
+ ulittle16_t CallInstructionSize;
+ TypeIndex Type;
+ };
+
+ HeapAllocationSiteSym(uint32_t RecordOffset, const Hdr *H)
+ : SymbolRecord(SymbolRecordKind::HeapAllocationSiteSym),
+ RecordOffset(RecordOffset), Header(*H) {}
+
+ static ErrorOr<HeapAllocationSiteSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ CV_DESERIALIZE(Data, H);
+
+ return HeapAllocationSiteSym(RecordOffset, H);
+ }
+
+ uint32_t getRelocationOffset() const {
+ return RecordOffset + offsetof(Hdr, CodeOffset);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+};
+
+// S_FRAMECOOKIE
+class FrameCookieSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t CodeOffset;
+ ulittle16_t Register;
+ uint8_t CookieKind;
+ uint8_t Flags;
+ };
+
+ FrameCookieSym(uint32_t RecordOffset, const Hdr *H)
+ : SymbolRecord(SymbolRecordKind::FrameCookieSym),
+ RecordOffset(RecordOffset), Header(*H) {}
+
+ static ErrorOr<FrameCookieSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ CV_DESERIALIZE(Data, H);
+
+ return FrameCookieSym(RecordOffset, H);
+ }
+
+ uint32_t getRelocationOffset() const {
+ return RecordOffset + offsetof(Hdr, CodeOffset);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+};
+
+// S_UDT, S_COBOLUDT
+class UDTSym : public SymbolRecord {
+public:
+ struct Hdr {
+ TypeIndex Type; // Type of the UDT
+ // Name: The null-terminated name follows.
+ };
+
+ UDTSym(uint32_t RecordOffset, const Hdr *H, StringRef Name)
+ : SymbolRecord(SymbolRecordKind::UDTSym), RecordOffset(RecordOffset),
+ Header(*H), Name(Name) {}
+
+ static ErrorOr<UDTSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return UDTSym(RecordOffset, H, Name);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+// S_BUILDINFO
+class BuildInfoSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t BuildId;
+ };
+
+ BuildInfoSym(uint32_t RecordOffset, const Hdr *H)
+ : SymbolRecord(SymbolRecordKind::BuildInfoSym),
+ RecordOffset(RecordOffset), Header(*H) {}
+
+ static ErrorOr<BuildInfoSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ CV_DESERIALIZE(Data, H);
+
+ return BuildInfoSym(RecordOffset, H);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+};
+
+// S_BPREL32
+class BPRelativeSym : public SymbolRecord {
+public:
+ struct Hdr {
+ little32_t Offset; // Offset from the base pointer register
+ TypeIndex Type; // Type of the variable
+ // Name: The null-terminated name follows.
+ };
+
+ BPRelativeSym(uint32_t RecordOffset, const Hdr *H, StringRef Name)
+ : SymbolRecord(SymbolRecordKind::BPRelativeSym),
+ RecordOffset(RecordOffset), Header(*H), Name(Name) {}
+
+ static ErrorOr<BPRelativeSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return BPRelativeSym(RecordOffset, H, Name);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+// S_REGREL32
+class RegRelativeSym : public SymbolRecord {
+public:
+ struct Hdr {
+ ulittle32_t Offset; // Offset from the register
+ TypeIndex Type; // Type of the variable
+ ulittle16_t Register; // Register to which the variable is relative
+ // Name: The null-terminated name follows.
+ };
+
+ RegRelativeSym(uint32_t RecordOffset, const Hdr *H, StringRef Name)
+ : SymbolRecord(SymbolRecordKind::RegRelativeSym),
+ RecordOffset(RecordOffset), Header(*H), Name(Name) {}
+
+ static ErrorOr<RegRelativeSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return RegRelativeSym(RecordOffset, H, Name);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+// S_CONSTANT, S_MANCONSTANT
+class ConstantSym : public SymbolRecord {
+public:
+ struct Hdr {
+ TypeIndex Type;
+ // Value: The value of the constant.
+ // Name: The null-terminated name follows.
+ };
+
+ ConstantSym(uint32_t RecordOffset, const Hdr *H, const APSInt &Value,
+ StringRef Name)
+ : SymbolRecord(SymbolRecordKind::ConstantSym), RecordOffset(RecordOffset),
+ Header(*H), Value(Value), Name(Name) {}
+
+ static ErrorOr<ConstantSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ APSInt Value;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Value, Name);
+
+ return ConstantSym(RecordOffset, H, Value, Name);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ APSInt Value;
+ StringRef Name;
+};
+
+// S_LDATA32, S_GDATA32, S_LMANDATA, S_GMANDATA
+class DataSym : public SymbolRecord {
+public:
+ struct Hdr {
+ TypeIndex Type;
+ ulittle32_t DataOffset;
+ ulittle16_t Segment;
+ // Name: The null-terminated name follows.
+ };
+
+ DataSym(uint32_t RecordOffset, const Hdr *H, StringRef Name)
+ : SymbolRecord(SymbolRecordKind::DataSym), RecordOffset(RecordOffset),
+ Header(*H), Name(Name) {}
+
+ static ErrorOr<DataSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return DataSym(RecordOffset, H, Name);
+ }
+
+ uint32_t getRelocationOffset() const {
+ return RecordOffset + offsetof(Hdr, DataOffset);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+// S_LTHREAD32, S_GTHREAD32
+class ThreadLocalDataSym : public SymbolRecord {
+public:
+ struct Hdr {
+ TypeIndex Type;
+ ulittle32_t DataOffset;
+ ulittle16_t Segment;
+ // Name: The null-terminated name follows.
+ };
+
+ ThreadLocalDataSym(uint32_t RecordOffset, const Hdr *H, StringRef Name)
+ : SymbolRecord(SymbolRecordKind::ThreadLocalDataSym),
+ RecordOffset(RecordOffset), Header(*H), Name(Name) {}
+
+ static ErrorOr<ThreadLocalDataSym> deserialize(SymbolRecordKind Kind,
+ uint32_t RecordOffset,
+ ArrayRef<uint8_t> &Data) {
+ const Hdr *H = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, H, Name);
+
+ return ThreadLocalDataSym(RecordOffset, H, Name);
+ }
+
+ uint32_t getRelocationOffset() const {
+ return RecordOffset + offsetof(Hdr, DataOffset);
+ }
+
+ uint32_t RecordOffset;
+ Hdr Header;
+ StringRef Name;
+};
+
+typedef CVRecord<SymbolKind> CVSymbol;
+typedef VarStreamArray<CVSymbol> CVSymbolArray;
+
+} // namespace codeview
+} // namespace llvm
+
+#endif
diff --git a/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h b/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h
new file mode 100644
index 0000000000000..a4965168c3db7
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h
@@ -0,0 +1,33 @@
+//===-- SymbolVisitorDelegate.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLVISITORDELEGATE_H
+#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLVISITORDELEGATE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <stdint.h>
+
+namespace llvm {
+
+namespace codeview {
+
+class SymbolVisitorDelegate {
+public:
+ virtual ~SymbolVisitorDelegate() {}
+
+ virtual uint32_t getRecordOffset(ArrayRef<uint8_t> Record) = 0;
+ virtual StringRef getFileNameForFileOffset(uint32_t FileOffset) = 0;
+ virtual StringRef getStringTable() = 0;
+};
+} // end namespace codeview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLVISITORDELEGATE_H
diff --git a/include/llvm/DebugInfo/CodeView/TypeDumper.h b/include/llvm/DebugInfo/CodeView/TypeDumper.h
new file mode 100644
index 0000000000000..ca79ab076e5eb
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/TypeDumper.h
@@ -0,0 +1,105 @@
+//===-- TypeDumper.h - CodeView type info dumper ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H
+#define LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+
+namespace llvm {
+class ScopedPrinter;
+
+namespace codeview {
+
+/// Dumper for CodeView type streams found in COFF object files and PDB files.
+class CVTypeDumper : public TypeVisitorCallbacks {
+public:
+ CVTypeDumper(ScopedPrinter *W, bool PrintRecordBytes)
+ : W(W), PrintRecordBytes(PrintRecordBytes) {}
+
+ StringRef getTypeName(TypeIndex TI);
+ void printTypeIndex(StringRef FieldName, TypeIndex TI);
+
+ /// Dumps one type record. Returns false if there was a type parsing error,
+ /// and true otherwise. This should be called in order, since the dumper
+ /// maintains state about previous records which are necessary for cross
+ /// type references.
+ Error dump(const CVRecord<TypeLeafKind> &Record);
+
+ /// Dumps the type records in Types. Returns false if there was a type stream
+ /// parse error, and true otherwise.
+ Error dump(const CVTypeArray &Types);
+
+ /// Dumps the type records in Data. Returns false if there was a type stream
+ /// parse error, and true otherwise. Use this method instead of the
+ /// CVTypeArray overload when type records are laid out contiguously in
+ /// memory.
+ Error dump(ArrayRef<uint8_t> Data);
+
+ /// Gets the type index for the next type record.
+ unsigned getNextTypeIndex() const {
+ return 0x1000 + CVUDTNames.size();
+ }
+
+ /// Records the name of a type, and reserves its type index.
+ void recordType(StringRef Name) { CVUDTNames.push_back(Name); }
+
+ /// Saves the name in a StringSet and creates a stable StringRef.
+ StringRef saveName(StringRef TypeName) {
+ return TypeNames.insert(TypeName).first->getKey();
+ }
+
+ void setPrinter(ScopedPrinter *P);
+ ScopedPrinter *getPrinter() { return W; }
+
+ /// Action to take on unknown types. By default, they are ignored.
+ Error visitUnknownType(const CVRecord<TypeLeafKind> &Record) override;
+ Error visitUnknownMember(const CVRecord<TypeLeafKind> &Record) override;
+
+ /// Paired begin/end actions for all types. Receives all record data,
+ /// including the fixed-length record prefix.
+ Error visitTypeBegin(const CVRecord<TypeLeafKind> &Record) override;
+ Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override;
+
+#define TYPE_RECORD(EnumName, EnumVal, Name) \
+ Error visit##Name(Name##Record &Record) override;
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ TYPE_RECORD(EnumName, EnumVal, Name)
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "TypeRecords.def"
+
+private:
+ void printMemberAttributes(MemberAttributes Attrs);
+ void printMemberAttributes(MemberAccess Access, MethodKind Kind,
+ MethodOptions Options);
+
+ ScopedPrinter *W;
+
+ bool PrintRecordBytes = false;
+
+ /// Name of the current type. Only valid before visitTypeEnd.
+ StringRef Name;
+
+ /// All user defined type records in .debug$T live in here. Type indices
+ /// greater than 0x1000 are user defined. Subtract 0x1000 from the index to
+ /// index into this vector.
+ SmallVector<StringRef, 10> CVUDTNames;
+
+ StringSet<> TypeNames;
+};
+
+} // end namespace codeview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H
diff --git a/include/llvm/DebugInfo/CodeView/TypeIndex.h b/include/llvm/DebugInfo/CodeView/TypeIndex.h
index d3a541be4c626..c2ebf3848892d 100644
--- a/include/llvm/DebugInfo/CodeView/TypeIndex.h
+++ b/include/llvm/DebugInfo/CodeView/TypeIndex.h
@@ -10,6 +10,7 @@
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEINDEX_H
#define LLVM_DEBUGINFO_CODEVIEW_TYPEINDEX_H
+#include "llvm/Support/Endian.h"
#include <cassert>
#include <cinttypes>
@@ -26,6 +27,8 @@ enum class SimpleTypeKind : uint32_t {
UnsignedCharacter = 0x0020, // 8 bit unsigned
NarrowCharacter = 0x0070, // really a char
WideCharacter = 0x0071, // wide char
+ Character16 = 0x007a, // char16_t
+ Character32 = 0x007b, // char32_t
SByte = 0x0068, // 8 bit signed int
Byte = 0x0069, // 8 bit unsigned int
@@ -41,6 +44,8 @@ enum class SimpleTypeKind : uint32_t {
UInt64Quad = 0x0023, // 64 bit unsigned
Int64 = 0x0076, // 64 bit signed int
UInt64 = 0x0077, // 64 bit unsigned int
+ Int128Oct = 0x0014, // 128 bit signed int
+ UInt128Oct = 0x0024, // 128 bit unsigned int
Int128 = 0x0078, // 128 bit signed int
UInt128 = 0x0079, // 128 bit unsigned int
@@ -52,15 +57,19 @@ enum class SimpleTypeKind : uint32_t {
Float80 = 0x0042, // 80 bit real
Float128 = 0x0043, // 128 bit real
- Complex32 = 0x0050, // 32 bit complex
- Complex64 = 0x0051, // 64 bit complex
- Complex80 = 0x0052, // 80 bit complex
- Complex128 = 0x0053, // 128 bit complex
-
- Boolean8 = 0x0030, // 8 bit boolean
- Boolean16 = 0x0031, // 16 bit boolean
- Boolean32 = 0x0032, // 32 bit boolean
- Boolean64 = 0x0033 // 64 bit boolean
+ Complex16 = 0x0056, // 16 bit complex
+ Complex32 = 0x0050, // 32 bit complex
+ Complex32PartialPrecision = 0x0055, // 32 bit PP complex
+ Complex48 = 0x0054, // 48 bit complex
+ Complex64 = 0x0051, // 64 bit complex
+ Complex80 = 0x0052, // 80 bit complex
+ Complex128 = 0x0053, // 128 bit complex
+
+ Boolean8 = 0x0030, // 8 bit boolean
+ Boolean16 = 0x0031, // 16 bit boolean
+ Boolean32 = 0x0032, // 32 bit boolean
+ Boolean64 = 0x0033, // 64 bit boolean
+ Boolean128 = 0x0034, // 128 bit boolean
};
enum class SimpleTypeMode : uint32_t {
@@ -74,6 +83,9 @@ enum class SimpleTypeMode : uint32_t {
NearPointer128 = 0x00000700 // 128 bit near pointer
};
+/// A 32-bit type reference. Types are indexed by their order of appearance in
+/// .debug$T plus 0x1000. Type indices less than 0x1000 are "simple" types,
+/// composed of a SimpleTypeMode byte followed by a SimpleTypeKind byte.
class TypeIndex {
public:
static const uint32_t FirstNonSimpleIndex = 0x1000;
@@ -91,6 +103,8 @@ public:
uint32_t getIndex() const { return Index; }
bool isSimple() const { return Index < FirstNonSimpleIndex; }
+ bool isNoneType() const { return *this == None(); }
+
SimpleTypeKind getSimpleKind() const {
assert(isSimple());
return static_cast<SimpleTypeKind>(Index & SimpleKindMask);
@@ -101,6 +115,7 @@ public:
return static_cast<SimpleTypeMode>(Index & SimpleModeMask);
}
+ static TypeIndex None() { return TypeIndex(SimpleTypeKind::None); }
static TypeIndex Void() { return TypeIndex(SimpleTypeKind::Void); }
static TypeIndex VoidPointer32() {
return TypeIndex(SimpleTypeKind::Void, SimpleTypeMode::NearPointer32);
@@ -143,33 +158,34 @@ public:
static TypeIndex Float32() { return TypeIndex(SimpleTypeKind::Float32); }
static TypeIndex Float64() { return TypeIndex(SimpleTypeKind::Float64); }
-private:
- uint32_t Index;
-};
+ friend inline bool operator==(const TypeIndex &A, const TypeIndex &B) {
+ return A.getIndex() == B.getIndex();
+ }
-inline bool operator==(const TypeIndex &A, const TypeIndex &B) {
- return A.getIndex() == B.getIndex();
-}
+ friend inline bool operator!=(const TypeIndex &A, const TypeIndex &B) {
+ return A.getIndex() != B.getIndex();
+ }
-inline bool operator!=(const TypeIndex &A, const TypeIndex &B) {
- return A.getIndex() != B.getIndex();
-}
+ friend inline bool operator<(const TypeIndex &A, const TypeIndex &B) {
+ return A.getIndex() < B.getIndex();
+ }
-inline bool operator<(const TypeIndex &A, const TypeIndex &B) {
- return A.getIndex() < B.getIndex();
-}
+ friend inline bool operator<=(const TypeIndex &A, const TypeIndex &B) {
+ return A.getIndex() <= B.getIndex();
+ }
-inline bool operator<=(const TypeIndex &A, const TypeIndex &B) {
- return A.getIndex() <= B.getIndex();
-}
+ friend inline bool operator>(const TypeIndex &A, const TypeIndex &B) {
+ return A.getIndex() > B.getIndex();
+ }
-inline bool operator>(const TypeIndex &A, const TypeIndex &B) {
- return A.getIndex() > B.getIndex();
-}
+ friend inline bool operator>=(const TypeIndex &A, const TypeIndex &B) {
+ return A.getIndex() >= B.getIndex();
+ }
+
+private:
+ support::ulittle32_t Index;
+};
-inline bool operator>=(const TypeIndex &A, const TypeIndex &B) {
- return A.getIndex() >= B.getIndex();
-}
}
}
diff --git a/include/llvm/DebugInfo/CodeView/TypeRecord.h b/include/llvm/DebugInfo/CodeView/TypeRecord.h
index 21755f5d9b09b..42751fbd4af11 100644
--- a/include/llvm/DebugInfo/CodeView/TypeRecord.h
+++ b/include/llvm/DebugInfo/CodeView/TypeRecord.h
@@ -10,15 +10,96 @@
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPERECORD_H
#define LLVM_DEBUGINFO_CODEVIEW_TYPERECORD_H
+#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/Support/ErrorOr.h"
#include <cinttypes>
+#include <utility>
namespace llvm {
namespace codeview {
+using llvm::support::little32_t;
+using llvm::support::ulittle16_t;
+using llvm::support::ulittle32_t;
+
+/// Equvalent to CV_fldattr_t in cvinfo.h.
+struct MemberAttributes {
+ ulittle16_t Attrs;
+ enum {
+ MethodKindShift = 2,
+ };
+
+ /// Get the access specifier. Valid for any kind of member.
+ MemberAccess getAccess() const {
+ return MemberAccess(unsigned(Attrs) & unsigned(MethodOptions::AccessMask));
+ }
+
+ /// Indicates if a method is defined with friend, virtual, static, etc.
+ MethodKind getMethodKind() const {
+ return MethodKind(
+ (unsigned(Attrs) & unsigned(MethodOptions::MethodKindMask)) >>
+ MethodKindShift);
+ }
+
+ /// Get the flags that are not included in access control or method
+ /// properties.
+ MethodOptions getFlags() const {
+ return MethodOptions(
+ unsigned(Attrs) &
+ ~unsigned(MethodOptions::AccessMask | MethodOptions::MethodKindMask));
+ }
+
+ /// Is this method virtual.
+ bool isVirtual() const {
+ auto MP = getMethodKind();
+ return MP != MethodKind::Vanilla && MP != MethodKind::Friend &&
+ MP != MethodKind::Static;
+ }
+
+ /// Does this member introduce a new virtual method.
+ bool isIntroducedVirtual() const {
+ auto MP = getMethodKind();
+ return MP == MethodKind::IntroducingVirtual ||
+ MP == MethodKind::PureIntroducingVirtual;
+ }
+};
+
+// Does not correspond to any tag, this is the tail of an LF_POINTER record
+// if it represents a member pointer.
+class MemberPointerInfo {
+public:
+ MemberPointerInfo() {}
+
+ MemberPointerInfo(TypeIndex ContainingType,
+ PointerToMemberRepresentation Representation)
+ : ContainingType(ContainingType), Representation(Representation) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<MemberPointerInfo> deserialize(ArrayRef<uint8_t> &Data);
+
+ TypeIndex getContainingType() const { return ContainingType; }
+ PointerToMemberRepresentation getRepresentation() const {
+ return Representation;
+ }
+
+private:
+ struct Layout {
+ TypeIndex ClassType;
+ ulittle16_t Representation; // PointerToMemberRepresentation
+ };
+
+ TypeIndex ContainingType;
+ PointerToMemberRepresentation Representation;
+};
+
class TypeRecord {
protected:
explicit TypeRecord(TypeRecordKind Kind) : Kind(Kind) {}
@@ -30,20 +111,34 @@ private:
TypeRecordKind Kind;
};
+// LF_MODIFIER
class ModifierRecord : public TypeRecord {
public:
- ModifierRecord(TypeIndex ModifiedType, ModifierOptions Options)
+ ModifierRecord(TypeIndex ModifiedType, ModifierOptions Modifiers)
: TypeRecord(TypeRecordKind::Modifier), ModifiedType(ModifiedType),
- Options(Options) {}
+ Modifiers(Modifiers) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<ModifierRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
TypeIndex getModifiedType() const { return ModifiedType; }
- ModifierOptions getOptions() const { return Options; }
+ ModifierOptions getModifiers() const { return Modifiers; }
private:
+ struct Layout {
+ TypeIndex ModifiedType;
+ ulittle16_t Modifiers; // ModifierOptions
+ };
+
TypeIndex ModifiedType;
- ModifierOptions Options;
+ ModifierOptions Modifiers;
};
+// LF_PROCEDURE
class ProcedureRecord : public TypeRecord {
public:
ProcedureRecord(TypeIndex ReturnType, CallingConvention CallConv,
@@ -53,6 +148,15 @@ public:
CallConv(CallConv), Options(Options), ParameterCount(ParameterCount),
ArgumentList(ArgumentList) {}
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<ProcedureRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ static uint32_t getLayoutSize() { return 2 + sizeof(Layout); }
+
TypeIndex getReturnType() const { return ReturnType; }
CallingConvention getCallConv() const { return CallConv; }
FunctionOptions getOptions() const { return Options; }
@@ -60,6 +164,14 @@ public:
TypeIndex getArgumentList() const { return ArgumentList; }
private:
+ struct Layout {
+ TypeIndex ReturnType;
+ CallingConvention CallConv;
+ FunctionOptions Options;
+ ulittle16_t NumParameters;
+ TypeIndex ArgListType;
+ };
+
TypeIndex ReturnType;
CallingConvention CallConv;
FunctionOptions Options;
@@ -67,6 +179,7 @@ private:
TypeIndex ArgumentList;
};
+// LF_MFUNCTION
class MemberFunctionRecord : public TypeRecord {
public:
MemberFunctionRecord(TypeIndex ReturnType, TypeIndex ClassType,
@@ -79,6 +192,13 @@ public:
ArgumentList(ArgumentList),
ThisPointerAdjustment(ThisPointerAdjustment) {}
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<MemberFunctionRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
TypeIndex getReturnType() const { return ReturnType; }
TypeIndex getClassType() const { return ClassType; }
TypeIndex getThisType() const { return ThisType; }
@@ -89,6 +209,17 @@ public:
int32_t getThisPointerAdjustment() const { return ThisPointerAdjustment; }
private:
+ struct Layout {
+ TypeIndex ReturnType;
+ TypeIndex ClassType;
+ TypeIndex ThisType;
+ CallingConvention CallConv;
+ FunctionOptions Options;
+ ulittle16_t NumParameters;
+ TypeIndex ArgListType;
+ little32_t ThisAdjustment;
+ };
+
TypeIndex ReturnType;
TypeIndex ClassType;
TypeIndex ThisType;
@@ -99,78 +230,210 @@ private:
int32_t ThisPointerAdjustment;
};
-class ArgumentListRecord : public TypeRecord {
+// LF_MFUNC_ID
+class MemberFuncIdRecord : public TypeRecord {
public:
- explicit ArgumentListRecord(llvm::ArrayRef<TypeIndex> ArgumentTypes)
- : TypeRecord(TypeRecordKind::ArgumentList), ArgumentTypes(ArgumentTypes) {
- }
+ MemberFuncIdRecord(TypeIndex ClassType, TypeIndex FunctionType,
+ StringRef Name)
+ : TypeRecord(TypeRecordKind::MemberFuncId), ClassType(ClassType),
+ FunctionType(FunctionType), Name(Name) {}
- llvm::ArrayRef<TypeIndex> getArgumentTypes() const { return ArgumentTypes; }
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<MemberFuncIdRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+ TypeIndex getClassType() const { return ClassType; }
+ TypeIndex getFunctionType() const { return FunctionType; }
+ StringRef getName() const { return Name; }
private:
- llvm::ArrayRef<TypeIndex> ArgumentTypes;
+ struct Layout {
+ TypeIndex ClassType;
+ TypeIndex FunctionType;
+ // Name: The null-terminated name follows.
+ };
+ TypeIndex ClassType;
+ TypeIndex FunctionType;
+ StringRef Name;
};
-class PointerRecordBase : public TypeRecord {
+// LF_ARGLIST, LF_SUBSTR_LIST
+class ArgListRecord : public TypeRecord {
public:
- PointerRecordBase(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode,
- PointerOptions Options, uint8_t Size)
+ ArgListRecord(TypeRecordKind Kind, ArrayRef<TypeIndex> Indices)
+ : TypeRecord(Kind), StringIndices(Indices) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<ArgListRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ ArrayRef<TypeIndex> getIndices() const { return StringIndices; }
+
+ static uint32_t getLayoutSize() { return 2 + sizeof(Layout); }
+
+private:
+ struct Layout {
+ ulittle32_t NumArgs; // Number of arguments
+ // ArgTypes[]: Type indicies of arguments
+ };
+
+ std::vector<TypeIndex> StringIndices;
+};
+
+// LF_POINTER
+class PointerRecord : public TypeRecord {
+public:
+ static const uint32_t PointerKindShift = 0;
+ static const uint32_t PointerKindMask = 0x1F;
+
+ static const uint32_t PointerModeShift = 5;
+ static const uint32_t PointerModeMask = 0x07;
+
+ static const uint32_t PointerSizeShift = 13;
+ static const uint32_t PointerSizeMask = 0xFF;
+
+ PointerRecord(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode,
+ PointerOptions Options, uint8_t Size)
+ : PointerRecord(ReferentType, Kind, Mode, Options, Size,
+ MemberPointerInfo()) {}
+
+ PointerRecord(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode,
+ PointerOptions Options, uint8_t Size,
+ const MemberPointerInfo &Member)
: TypeRecord(TypeRecordKind::Pointer), ReferentType(ReferentType),
- PtrKind(Kind), Mode(Mode), Options(Options), Size(Size) {}
+ PtrKind(Kind), Mode(Mode), Options(Options), Size(Size),
+ MemberInfo(Member) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<PointerRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
TypeIndex getReferentType() const { return ReferentType; }
PointerKind getPointerKind() const { return PtrKind; }
PointerMode getMode() const { return Mode; }
PointerOptions getOptions() const { return Options; }
uint8_t getSize() const { return Size; }
+ MemberPointerInfo getMemberInfo() const { return MemberInfo; }
+
+ bool isPointerToMember() const {
+ return Mode == PointerMode::PointerToDataMember ||
+ Mode == PointerMode::PointerToMemberFunction;
+ }
+ bool isFlat() const {
+ return !!(uint32_t(Options) & uint32_t(PointerOptions::Flat32));
+ }
+ bool isConst() const {
+ return !!(uint32_t(Options) & uint32_t(PointerOptions::Const));
+ }
+ bool isVolatile() const {
+ return !!(uint32_t(Options) & uint32_t(PointerOptions::Volatile));
+ }
+ bool isUnaligned() const {
+ return !!(uint32_t(Options) & uint32_t(PointerOptions::Unaligned));
+ }
private:
+ struct Layout {
+ TypeIndex PointeeType;
+ ulittle32_t Attrs; // pointer attributes
+ // if pointer to member:
+ // PointerToMemberTail
+ PointerKind getPtrKind() const {
+ return PointerKind(Attrs & PointerKindMask);
+ }
+ PointerMode getPtrMode() const {
+ return PointerMode((Attrs >> PointerModeShift) & PointerModeMask);
+ }
+ uint8_t getPtrSize() const {
+ return (Attrs >> PointerSizeShift) & PointerSizeMask;
+ }
+ bool isFlat() const { return Attrs & (1 << 8); }
+ bool isVolatile() const { return Attrs & (1 << 9); }
+ bool isConst() const { return Attrs & (1 << 10); }
+ bool isUnaligned() const { return Attrs & (1 << 11); }
+
+ bool isPointerToDataMember() const {
+ return getPtrMode() == PointerMode::PointerToDataMember;
+ }
+ bool isPointerToMemberFunction() const {
+ return getPtrMode() == PointerMode::PointerToMemberFunction;
+ }
+ bool isPointerToMember() const {
+ return isPointerToMemberFunction() || isPointerToDataMember();
+ }
+ };
+
TypeIndex ReferentType;
PointerKind PtrKind;
PointerMode Mode;
PointerOptions Options;
uint8_t Size;
+ MemberPointerInfo MemberInfo;
};
-class PointerRecord : public PointerRecordBase {
+// LF_NESTTYPE
+class NestedTypeRecord : public TypeRecord {
public:
- PointerRecord(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode,
- PointerOptions Options, uint8_t Size)
- : PointerRecordBase(ReferentType, Kind, Mode, Options, Size) {}
-};
+ NestedTypeRecord(TypeIndex Type, StringRef Name)
+ : TypeRecord(TypeRecordKind::NestedType), Type(Type), Name(Name) {}
-class PointerToMemberRecord : public PointerRecordBase {
-public:
- PointerToMemberRecord(TypeIndex ReferentType, PointerKind Kind,
- PointerMode Mode, PointerOptions Options, uint8_t Size,
- TypeIndex ContainingType,
- PointerToMemberRepresentation Representation)
- : PointerRecordBase(ReferentType, Kind, Mode, Options, Size),
- ContainingType(ContainingType), Representation(Representation) {}
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
- TypeIndex getContainingType() const { return ContainingType; }
- PointerToMemberRepresentation getRepresentation() const {
- return Representation;
- }
+ static ErrorOr<NestedTypeRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ TypeIndex getNestedType() const { return Type; }
+ StringRef getName() const { return Name; }
private:
- TypeIndex ContainingType;
- PointerToMemberRepresentation Representation;
+ struct Layout {
+ ulittle16_t Pad0; // Should be zero
+ TypeIndex Type; // Type index of nested type
+ // Name: Null-terminated string
+ };
+
+ TypeIndex Type;
+ StringRef Name;
};
+// LF_ARRAY
class ArrayRecord : public TypeRecord {
public:
ArrayRecord(TypeIndex ElementType, TypeIndex IndexType, uint64_t Size,
- llvm::StringRef Name)
+ StringRef Name)
: TypeRecord(TypeRecordKind::Array), ElementType(ElementType),
IndexType(IndexType), Size(Size), Name(Name) {}
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<ArrayRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
TypeIndex getElementType() const { return ElementType; }
TypeIndex getIndexType() const { return IndexType; }
uint64_t getSize() const { return Size; }
llvm::StringRef getName() const { return Name; }
private:
+ struct Layout {
+ TypeIndex ElementType;
+ TypeIndex IndexType;
+ // SizeOf: LF_NUMERIC encoded size in bytes. Not element count!
+ // Name: The null-terminated name follows.
+ };
+
TypeIndex ElementType;
TypeIndex IndexType;
uint64_t Size;
@@ -185,6 +448,15 @@ protected:
FieldList(FieldList), Name(Name), UniqueName(UniqueName) {}
public:
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static const int HfaKindShift = 11;
+ static const int HfaKindMask = 0x1800;
+ static const int WinRTKindShift = 14;
+ static const int WinRTKindMask = 0xC000;
+
uint16_t getMemberCount() const { return MemberCount; }
ClassOptions getOptions() const { return Options; }
TypeIndex getFieldList() const { return FieldList; }
@@ -199,17 +471,24 @@ private:
StringRef UniqueName;
};
-class AggregateRecord : public TagRecord {
+// LF_CLASS, LF_STRUCTURE, LF_INTERFACE
+class ClassRecord : public TagRecord {
public:
- AggregateRecord(TypeRecordKind Kind, uint16_t MemberCount,
- ClassOptions Options, HfaKind Hfa,
- WindowsRTClassKind WinRTKind, TypeIndex FieldList,
- TypeIndex DerivationList, TypeIndex VTableShape,
- uint64_t Size, StringRef Name, StringRef UniqueName)
+ ClassRecord(TypeRecordKind Kind, uint16_t MemberCount, ClassOptions Options,
+ HfaKind Hfa, WindowsRTClassKind WinRTKind, TypeIndex FieldList,
+ TypeIndex DerivationList, TypeIndex VTableShape, uint64_t Size,
+ StringRef Name, StringRef UniqueName)
: TagRecord(Kind, MemberCount, Options, FieldList, Name, UniqueName),
Hfa(Hfa), WinRTKind(WinRTKind), DerivationList(DerivationList),
VTableShape(VTableShape), Size(Size) {}
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<ClassRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
HfaKind getHfa() const { return Hfa; }
WindowsRTClassKind getWinRTKind() const { return WinRTKind; }
TypeIndex getDerivationList() const { return DerivationList; }
@@ -217,6 +496,21 @@ public:
uint64_t getSize() const { return Size; }
private:
+ struct Layout {
+ ulittle16_t MemberCount; // Number of members in FieldList.
+ ulittle16_t Properties; // ClassOptions bitset
+ TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members
+ TypeIndex DerivedFrom; // LF_DERIVED: List of known derived classes
+ TypeIndex VShape; // LF_VTSHAPE: Shape of the vftable
+ // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC
+ // integer.
+ // Name: The null-terminated name follows.
+
+ bool hasUniqueName() const {
+ return Properties & uint16_t(ClassOptions::HasUniqueName);
+ }
+ };
+
HfaKind Hfa;
WindowsRTClassKind WinRTKind;
TypeIndex DerivationList;
@@ -224,6 +518,40 @@ private:
uint64_t Size;
};
+// LF_UNION
+struct UnionRecord : public TagRecord {
+ UnionRecord(uint16_t MemberCount, ClassOptions Options, HfaKind Hfa,
+ TypeIndex FieldList, uint64_t Size, StringRef Name,
+ StringRef UniqueName)
+ : TagRecord(TypeRecordKind::Union, MemberCount, Options, FieldList, Name,
+ UniqueName),
+ Hfa(Hfa), Size(Size) {}
+
+ static ErrorOr<UnionRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ HfaKind getHfa() const { return Hfa; }
+ uint64_t getSize() const { return Size; }
+
+private:
+ struct Layout {
+ ulittle16_t MemberCount; // Number of members in FieldList.
+ ulittle16_t Properties; // ClassOptions bitset
+ TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members
+ // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC
+ // integer.
+ // Name: The null-terminated name follows.
+
+ bool hasUniqueName() const {
+ return Properties & uint16_t(ClassOptions::HasUniqueName);
+ }
+ };
+
+ HfaKind Hfa;
+ uint64_t Size;
+};
+
+// LF_ENUM
class EnumRecord : public TagRecord {
public:
EnumRecord(uint16_t MemberCount, ClassOptions Options, TypeIndex FieldList,
@@ -232,38 +560,642 @@ public:
UniqueName),
UnderlyingType(UnderlyingType) {}
+ /// Rewrite member type indices with IndexMap. Returns false if a type index is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<EnumRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
TypeIndex getUnderlyingType() const { return UnderlyingType; }
private:
+ struct Layout {
+ ulittle16_t NumEnumerators; // Number of enumerators
+ ulittle16_t Properties;
+ TypeIndex UnderlyingType;
+ TypeIndex FieldListType;
+ // Name: The null-terminated name follows.
+
+ bool hasUniqueName() const {
+ return Properties & uint16_t(ClassOptions::HasUniqueName);
+ }
+ };
+
TypeIndex UnderlyingType;
};
-class BitFieldRecord : TypeRecord {
+// LF_BITFIELD
+class BitFieldRecord : public TypeRecord {
public:
BitFieldRecord(TypeIndex Type, uint8_t BitSize, uint8_t BitOffset)
: TypeRecord(TypeRecordKind::BitField), Type(Type), BitSize(BitSize),
BitOffset(BitOffset) {}
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<BitFieldRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
TypeIndex getType() const { return Type; }
uint8_t getBitOffset() const { return BitOffset; }
uint8_t getBitSize() const { return BitSize; }
private:
+ struct Layout {
+ TypeIndex Type;
+ uint8_t BitSize;
+ uint8_t BitOffset;
+ };
+
TypeIndex Type;
uint8_t BitSize;
uint8_t BitOffset;
};
-class VirtualTableShapeRecord : TypeRecord {
+// LF_VTSHAPE
+class VFTableShapeRecord : public TypeRecord {
+public:
+ explicit VFTableShapeRecord(ArrayRef<VFTableSlotKind> Slots)
+ : TypeRecord(TypeRecordKind::VFTableShape), SlotsRef(Slots) {}
+ explicit VFTableShapeRecord(std::vector<VFTableSlotKind> Slots)
+ : TypeRecord(TypeRecordKind::VFTableShape), Slots(std::move(Slots)) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<VFTableShapeRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ ArrayRef<VFTableSlotKind> getSlots() const {
+ if (!SlotsRef.empty())
+ return SlotsRef;
+ return Slots;
+ }
+ uint32_t getEntryCount() const { return getSlots().size(); }
+
+private:
+ struct Layout {
+ // Number of vftable entries. Each method may have more than one entry due
+ // to
+ // things like covariant return types.
+ ulittle16_t VFEntryCount;
+ // Descriptors[]: 4-bit virtual method descriptors of type CV_VTS_desc_e.
+ };
+
+private:
+ ArrayRef<VFTableSlotKind> SlotsRef;
+ std::vector<VFTableSlotKind> Slots;
+};
+
+// LF_TYPESERVER2
+class TypeServer2Record : public TypeRecord {
+public:
+ TypeServer2Record(StringRef Guid, uint32_t Age, StringRef Name)
+ : TypeRecord(TypeRecordKind::TypeServer2), Guid(Guid), Age(Age),
+ Name(Name) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<TypeServer2Record> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ StringRef getGuid() const { return Guid; }
+
+ uint32_t getAge() const { return Age; }
+
+ StringRef getName() const { return Name; }
+
+private:
+ struct Layout {
+ char Guid[16]; // GUID
+ ulittle32_t Age;
+ // Name: Name of the PDB as a null-terminated string
+ };
+
+ StringRef Guid;
+ uint32_t Age;
+ StringRef Name;
+};
+
+// LF_STRING_ID
+class StringIdRecord : public TypeRecord {
+public:
+ StringIdRecord(TypeIndex Id, StringRef String)
+ : TypeRecord(TypeRecordKind::StringId), Id(Id), String(String) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<StringIdRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ TypeIndex getId() const { return Id; }
+
+ StringRef getString() const { return String; }
+
+private:
+ struct Layout {
+ TypeIndex id;
+ // Name: Name of the PDB as a null-terminated string
+ };
+
+ TypeIndex Id;
+ StringRef String;
+};
+
+// LF_FUNC_ID
+class FuncIdRecord : public TypeRecord {
+public:
+ FuncIdRecord(TypeIndex ParentScope, TypeIndex FunctionType, StringRef Name)
+ : TypeRecord(TypeRecordKind::FuncId), ParentScope(ParentScope),
+ FunctionType(FunctionType), Name(Name) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<FuncIdRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ TypeIndex getParentScope() const { return ParentScope; }
+
+ TypeIndex getFunctionType() const { return FunctionType; }
+
+ StringRef getName() const { return Name; }
+
+private:
+ struct Layout {
+ TypeIndex ParentScope;
+ TypeIndex FunctionType;
+ // Name: The null-terminated name follows.
+ };
+
+ TypeIndex ParentScope;
+ TypeIndex FunctionType;
+ StringRef Name;
+};
+
+// LF_UDT_SRC_LINE
+class UdtSourceLineRecord : public TypeRecord {
public:
- explicit VirtualTableShapeRecord(ArrayRef<VirtualTableSlotKind> Slots)
- : TypeRecord(TypeRecordKind::VirtualTableShape), Slots(Slots) {}
+ UdtSourceLineRecord(TypeIndex UDT, TypeIndex SourceFile, uint32_t LineNumber)
+ : TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT),
+ SourceFile(SourceFile), LineNumber(LineNumber) {}
- ArrayRef<VirtualTableSlotKind> getSlots() const { return Slots; }
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<UdtSourceLineRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ TypeIndex getUDT() const { return UDT; }
+ TypeIndex getSourceFile() const { return SourceFile; }
+ uint32_t getLineNumber() const { return LineNumber; }
private:
- ArrayRef<VirtualTableSlotKind> Slots;
+ struct Layout {
+ TypeIndex UDT; // The user-defined type
+ TypeIndex SourceFile; // StringID containing the source filename
+ ulittle32_t LineNumber;
+ };
+
+ TypeIndex UDT;
+ TypeIndex SourceFile;
+ uint32_t LineNumber;
};
+
+// LF_UDT_MOD_SRC_LINE
+class UdtModSourceLineRecord : public TypeRecord {
+public:
+ UdtModSourceLineRecord(TypeIndex UDT, TypeIndex SourceFile,
+ uint32_t LineNumber, uint16_t Module)
+ : TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT),
+ SourceFile(SourceFile), LineNumber(LineNumber), Module(Module) {}
+
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<UdtModSourceLineRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ CV_DESERIALIZE(Data, L);
+
+ return UdtModSourceLineRecord(L->UDT, L->SourceFile, L->LineNumber,
+ L->Module);
+ }
+
+ TypeIndex getUDT() const { return UDT; }
+ TypeIndex getSourceFile() const { return SourceFile; }
+ uint32_t getLineNumber() const { return LineNumber; }
+ uint16_t getModule() const { return Module; }
+
+private:
+ struct Layout {
+ TypeIndex UDT; // The user-defined type
+ TypeIndex SourceFile; // StringID containing the source filename
+ ulittle32_t LineNumber;
+ ulittle16_t Module; // Module that contributes this UDT definition
+ };
+
+ TypeIndex UDT;
+ TypeIndex SourceFile;
+ uint32_t LineNumber;
+ uint16_t Module;
+};
+
+// LF_BUILDINFO
+class BuildInfoRecord : public TypeRecord {
+public:
+ BuildInfoRecord(ArrayRef<TypeIndex> ArgIndices)
+ : TypeRecord(TypeRecordKind::BuildInfo),
+ ArgIndices(ArgIndices.begin(), ArgIndices.end()) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<BuildInfoRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ ArrayRef<TypeIndex> getArgs() const { return ArgIndices; }
+
+private:
+ struct Layout {
+ ulittle16_t NumArgs; // Number of arguments
+ // ArgTypes[]: Type indicies of arguments
+ };
+ SmallVector<TypeIndex, 4> ArgIndices;
+};
+
+// LF_VFTABLE
+class VFTableRecord : public TypeRecord {
+public:
+ VFTableRecord(TypeIndex CompleteClass, TypeIndex OverriddenVFTable,
+ uint32_t VFPtrOffset, StringRef Name,
+ ArrayRef<StringRef> Methods)
+ : TypeRecord(TypeRecordKind::VFTable),
+ CompleteClass(CompleteClass), OverriddenVFTable(OverriddenVFTable),
+ VFPtrOffset(VFPtrOffset), Name(Name), MethodNamesRef(Methods) {}
+ VFTableRecord(TypeIndex CompleteClass, TypeIndex OverriddenVFTable,
+ uint32_t VFPtrOffset, StringRef Name,
+ const std::vector<StringRef> &Methods)
+ : TypeRecord(TypeRecordKind::VFTable),
+ CompleteClass(CompleteClass), OverriddenVFTable(OverriddenVFTable),
+ VFPtrOffset(VFPtrOffset), Name(Name), MethodNames(Methods) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<VFTableRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ TypeIndex getCompleteClass() const { return CompleteClass; }
+ TypeIndex getOverriddenVTable() const { return OverriddenVFTable; }
+ uint32_t getVFPtrOffset() const { return VFPtrOffset; }
+ StringRef getName() const { return Name; }
+ ArrayRef<StringRef> getMethodNames() const {
+ if (!MethodNamesRef.empty())
+ return MethodNamesRef;
+ return MethodNames;
+ }
+
+private:
+ struct Layout {
+ TypeIndex CompleteClass; // Class that owns this vftable.
+ TypeIndex OverriddenVFTable; // VFTable that this overrides.
+ ulittle32_t VFPtrOffset; // VFPtr offset in CompleteClass
+ ulittle32_t NamesLen; // Length of subsequent names array in bytes.
+ // Names: A sequence of null-terminated strings. First string is vftable
+ // names.
+ };
+
+ TypeIndex CompleteClass;
+ TypeIndex OverriddenVFTable;
+ ulittle32_t VFPtrOffset;
+ StringRef Name;
+ ArrayRef<StringRef> MethodNamesRef;
+ std::vector<StringRef> MethodNames;
+};
+
+// LF_ONEMETHOD
+class OneMethodRecord : public TypeRecord {
+public:
+ OneMethodRecord(TypeIndex Type, MethodKind Kind, MethodOptions Options,
+ MemberAccess Access, int32_t VFTableOffset, StringRef Name)
+ : TypeRecord(TypeRecordKind::OneMethod), Type(Type), Kind(Kind),
+ Options(Options), Access(Access), VFTableOffset(VFTableOffset),
+ Name(Name) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<OneMethodRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ TypeIndex getType() const { return Type; }
+ MethodKind getKind() const { return Kind; }
+ MethodOptions getOptions() const { return Options; }
+ MemberAccess getAccess() const { return Access; }
+ int32_t getVFTableOffset() const { return VFTableOffset; }
+ StringRef getName() const { return Name; }
+
+ bool isIntroducingVirtual() const {
+ return Kind == MethodKind::IntroducingVirtual ||
+ Kind == MethodKind::PureIntroducingVirtual;
+ }
+
+private:
+ struct Layout {
+ MemberAttributes Attrs;
+ TypeIndex Type;
+ // If is introduced virtual method:
+ // VFTableOffset: int32_t offset in vftable
+ // Name: Null-terminated string
+ };
+
+ TypeIndex Type;
+ MethodKind Kind;
+ MethodOptions Options;
+ MemberAccess Access;
+ int32_t VFTableOffset;
+ StringRef Name;
+};
+
+// LF_METHODLIST
+class MethodOverloadListRecord : public TypeRecord {
+public:
+ MethodOverloadListRecord(ArrayRef<OneMethodRecord> Methods)
+ : TypeRecord(TypeRecordKind::MethodOverloadList), Methods(Methods) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<MethodOverloadListRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ ArrayRef<OneMethodRecord> getMethods() const { return Methods; }
+
+private:
+ struct Layout {
+ MemberAttributes Attrs;
+ ulittle16_t Padding;
+
+ TypeIndex Type;
+ // If is introduced virtual method:
+ // VFTableOffset: int32_t offset in vftable
+ };
+
+ std::vector<OneMethodRecord> Methods;
+};
+
+/// For method overload sets. LF_METHOD
+class OverloadedMethodRecord : public TypeRecord {
+public:
+ OverloadedMethodRecord(uint16_t NumOverloads, TypeIndex MethodList,
+ StringRef Name)
+ : TypeRecord(TypeRecordKind::OverloadedMethod),
+ NumOverloads(NumOverloads), MethodList(MethodList), Name(Name) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<OverloadedMethodRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ uint16_t getNumOverloads() const { return NumOverloads; }
+ TypeIndex getMethodList() const { return MethodList; }
+ StringRef getName() const { return Name; }
+
+private:
+ struct Layout {
+ ulittle16_t MethodCount; // Size of overload set
+ TypeIndex MethList; // Type index of methods in overload set
+ // Name: Null-terminated string
+ };
+
+ uint16_t NumOverloads;
+ TypeIndex MethodList;
+ StringRef Name;
+};
+
+// LF_MEMBER
+class DataMemberRecord : public TypeRecord {
+public:
+ DataMemberRecord(MemberAccess Access, TypeIndex Type, uint64_t Offset,
+ StringRef Name)
+ : TypeRecord(TypeRecordKind::DataMember), Access(Access), Type(Type),
+ FieldOffset(Offset), Name(Name) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<DataMemberRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ MemberAccess getAccess() const { return Access; }
+ TypeIndex getType() const { return Type; }
+ uint64_t getFieldOffset() const { return FieldOffset; }
+ StringRef getName() const { return Name; }
+
+private:
+ struct Layout {
+ MemberAttributes Attrs; // Access control attributes, etc
+ TypeIndex Type;
+ // FieldOffset: LF_NUMERIC encoded byte offset
+ // Name: Null-terminated string
+ };
+
+ MemberAccess Access;
+ TypeIndex Type;
+ uint64_t FieldOffset;
+ StringRef Name;
+};
+
+// LF_STMEMBER
+class StaticDataMemberRecord : public TypeRecord {
+public:
+ StaticDataMemberRecord(MemberAccess Access, TypeIndex Type, StringRef Name)
+ : TypeRecord(TypeRecordKind::StaticDataMember), Access(Access),
+ Type(Type), Name(Name) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<StaticDataMemberRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ MemberAccess getAccess() const { return Access; }
+ TypeIndex getType() const { return Type; }
+ StringRef getName() const { return Name; }
+
+private:
+ struct Layout {
+ MemberAttributes Attrs; // Access control attributes, etc
+ TypeIndex Type;
+ // Name: Null-terminated string
+ };
+
+ MemberAccess Access;
+ TypeIndex Type;
+ StringRef Name;
+};
+
+// LF_ENUMERATE
+class EnumeratorRecord : public TypeRecord {
+public:
+ EnumeratorRecord(MemberAccess Access, APSInt Value, StringRef Name)
+ : TypeRecord(TypeRecordKind::Enumerator), Access(Access),
+ Value(std::move(Value)), Name(Name) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<EnumeratorRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ MemberAccess getAccess() const { return Access; }
+ APSInt getValue() const { return Value; }
+ StringRef getName() const { return Name; }
+
+private:
+ struct Layout {
+ MemberAttributes Attrs; // Access control attributes, etc
+ // EnumValue: LF_NUMERIC encoded enumerator value
+ // Name: Null-terminated string
+ };
+
+ MemberAccess Access;
+ APSInt Value;
+ StringRef Name;
+};
+
+// LF_VFUNCTAB
+class VFPtrRecord : public TypeRecord {
+public:
+ VFPtrRecord(TypeIndex Type)
+ : TypeRecord(TypeRecordKind::VFPtr), Type(Type) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<VFPtrRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ TypeIndex getType() const { return Type; }
+
+private:
+ struct Layout {
+ ulittle16_t Pad0;
+ TypeIndex Type; // Type of vfptr
+ };
+ TypeIndex Type;
+};
+
+// LF_BCLASS, LF_BINTERFACE
+class BaseClassRecord : public TypeRecord {
+public:
+ BaseClassRecord(MemberAccess Access, TypeIndex Type, uint64_t Offset)
+ : TypeRecord(TypeRecordKind::BaseClass), Access(Access), Type(Type),
+ Offset(Offset) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<BaseClassRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ MemberAccess getAccess() const { return Access; }
+ TypeIndex getBaseType() const { return Type; }
+ uint64_t getBaseOffset() const { return Offset; }
+
+private:
+ struct Layout {
+ MemberAttributes Attrs; // Access control attributes, etc
+ TypeIndex BaseType; // Base class type
+ // BaseOffset: LF_NUMERIC encoded byte offset of base from derived.
+ };
+ MemberAccess Access;
+ TypeIndex Type;
+ uint64_t Offset;
+};
+
+// LF_VBCLASS, LF_IVBCLASS
+class VirtualBaseClassRecord : public TypeRecord {
+public:
+ VirtualBaseClassRecord(MemberAccess Access, TypeIndex BaseType,
+ TypeIndex VBPtrType, uint64_t Offset, uint64_t Index)
+ : TypeRecord(TypeRecordKind::VirtualBaseClass), Access(Access),
+ BaseType(BaseType), VBPtrType(VBPtrType), VBPtrOffset(Offset),
+ VTableIndex(Index) {}
+
+ /// Rewrite member type indices with IndexMap. Returns false if a type index
+ /// is not in the map.
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<VirtualBaseClassRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+ MemberAccess getAccess() const { return Access; }
+ TypeIndex getBaseType() const { return BaseType; }
+ TypeIndex getVBPtrType() const { return VBPtrType; }
+ uint64_t getVBPtrOffset() const { return VBPtrOffset; }
+ uint64_t getVTableIndex() const { return VTableIndex; }
+
+private:
+ struct Layout {
+ MemberAttributes Attrs; // Access control attributes, etc.
+ TypeIndex BaseType; // Base class type
+ TypeIndex VBPtrType; // Virtual base pointer type
+ // VBPtrOffset: Offset of vbptr from vfptr encoded as LF_NUMERIC.
+ // VBTableIndex: Index of vbase within vbtable encoded as LF_NUMERIC.
+ };
+ MemberAccess Access;
+ TypeIndex BaseType;
+ TypeIndex VBPtrType;
+ uint64_t VBPtrOffset;
+ uint64_t VTableIndex;
+};
+
+/// LF_INDEX - Used to chain two large LF_FIELDLIST or LF_METHODLIST records
+/// together. The first will end in an LF_INDEX record that points to the next.
+class ListContinuationRecord : public TypeRecord {
+public:
+ ListContinuationRecord(TypeIndex ContinuationIndex)
+ : TypeRecord(TypeRecordKind::ListContinuation),
+ ContinuationIndex(ContinuationIndex) {}
+
+ TypeIndex getContinuationIndex() const { return ContinuationIndex; }
+
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<ListContinuationRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+private:
+ struct Layout {
+ ulittle16_t Pad0;
+ TypeIndex ContinuationIndex;
+ };
+ TypeIndex ContinuationIndex;
+};
+
+typedef CVRecord<TypeLeafKind> CVType;
+typedef VarStreamArray<CVType> CVTypeArray;
}
}
diff --git a/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h b/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h
index 1f48cf70666df..eb7993baab894 100644
--- a/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h
+++ b/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h
@@ -10,9 +10,10 @@
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPERECORDBUILDER_H
#define LLVM_DEBUGINFO_CODEVIEW_TYPERECORDBUILDER_H
+#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
-#include "llvm/ADT/SmallVector.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/raw_ostream.h"
@@ -39,13 +40,25 @@ public:
void writeEncodedInteger(int64_t Value);
void writeEncodedSignedInteger(int64_t Value);
void writeEncodedUnsignedInteger(uint64_t Value);
- void writeNullTerminatedString(const char *Value);
void writeNullTerminatedString(StringRef Value);
+ void writeGuid(StringRef Guid);
+ void writeBytes(StringRef Value) { Stream << Value; }
llvm::StringRef str();
uint64_t size() const { return Stream.tell(); }
+ void truncate(uint64_t Size) {
+ // This works because raw_svector_ostream is not buffered.
+ assert(Size < Buffer.size());
+ Buffer.resize(Size);
+ }
+
+ void reset(TypeRecordKind K) {
+ Buffer.clear();
+ writeTypeRecordKind(K);
+ }
+
private:
llvm::SmallVector<char, 256> Buffer;
llvm::raw_svector_ostream Stream;
diff --git a/include/llvm/DebugInfo/CodeView/TypeRecords.def b/include/llvm/DebugInfo/CodeView/TypeRecords.def
new file mode 100644
index 0000000000000..0959f4bf19c71
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/TypeRecords.def
@@ -0,0 +1,252 @@
+
+//===-- CVLeafTypes.def - All CodeView leaf types ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// See LEAF_ENUM_e in cvinfo.h. This should match the constants there.
+//
+//===----------------------------------------------------------------------===//
+
+// If the type is known, then we have a record describing it in TypeRecord.h.
+
+#ifndef CV_TYPE
+#define CV_TYPE(lf_ename, value)
+#endif
+
+// If the type is known, then we have a record describing it in TypeRecord.h.
+#ifndef TYPE_RECORD
+#define TYPE_RECORD(lf_ename, value, name) CV_TYPE(lf_ename, value)
+#endif
+
+#ifndef TYPE_RECORD_ALIAS
+#define TYPE_RECORD_ALIAS(lf_ename, value, name, alias_name) \
+ TYPE_RECORD(lf_ename, value, name)
+#endif
+
+#ifndef MEMBER_RECORD
+#define MEMBER_RECORD(lf_ename, value, name) TYPE_RECORD(lf_ename, value, name)
+#endif
+
+#ifndef MEMBER_RECORD_ALIAS
+#define MEMBER_RECORD_ALIAS(lf_ename, value, name, alias_name) \
+ MEMBER_RECORD(lf_ename, value, name)
+#endif
+
+TYPE_RECORD(LF_POINTER, 0x1002, Pointer)
+TYPE_RECORD(LF_MODIFIER, 0x1001, Modifier)
+TYPE_RECORD(LF_PROCEDURE, 0x1008, Procedure)
+TYPE_RECORD(LF_MFUNCTION, 0x1009, MemberFunction)
+TYPE_RECORD(LF_ARGLIST, 0x1201, ArgList)
+
+TYPE_RECORD(LF_ARRAY, 0x1503, Array)
+TYPE_RECORD(LF_CLASS, 0x1504, Class)
+TYPE_RECORD_ALIAS(LF_STRUCTURE, 0x1505, Struct, Class)
+TYPE_RECORD_ALIAS(LF_INTERFACE, 0x1519, Interface, Class)
+TYPE_RECORD(LF_UNION, 0x1506, Union)
+TYPE_RECORD(LF_ENUM, 0x1507, Enum)
+TYPE_RECORD(LF_TYPESERVER2, 0x1515, TypeServer2)
+TYPE_RECORD(LF_VFTABLE, 0x151d, VFTable)
+TYPE_RECORD(LF_VTSHAPE, 0x000a, VFTableShape)
+
+TYPE_RECORD(LF_BITFIELD, 0x1205, BitField)
+
+// Member type records. These are generally not length prefixed, and appear
+// inside of a field list record.
+MEMBER_RECORD(LF_BCLASS, 0x1400, BaseClass)
+MEMBER_RECORD_ALIAS(LF_BINTERFACE, 0x151a, BaseInterface, BaseClass)
+
+MEMBER_RECORD(LF_VBCLASS, 0x1401, VirtualBaseClass)
+MEMBER_RECORD_ALIAS(LF_IVBCLASS, 0x1402, IndirectVirtualBaseClass,
+ VirtualBaseClass)
+
+MEMBER_RECORD(LF_VFUNCTAB, 0x1409, VFPtr)
+MEMBER_RECORD(LF_STMEMBER, 0x150e, StaticDataMember)
+MEMBER_RECORD(LF_METHOD, 0x150f, OverloadedMethod)
+MEMBER_RECORD(LF_MEMBER, 0x150d, DataMember)
+MEMBER_RECORD(LF_NESTTYPE, 0x1510, NestedType)
+MEMBER_RECORD(LF_ONEMETHOD, 0x1511, OneMethod)
+MEMBER_RECORD(LF_ENUMERATE, 0x1502, Enumerator)
+MEMBER_RECORD(LF_INDEX, 0x1404, ListContinuation)
+
+// ID leaf records. Subsequent leaf types may be referenced from .debug$S.
+TYPE_RECORD(LF_FUNC_ID, 0x1601, FuncId)
+TYPE_RECORD(LF_MFUNC_ID, 0x1602, MemberFuncId)
+TYPE_RECORD(LF_BUILDINFO, 0x1603, BuildInfo)
+// FIXME: We reuse the structure of ArgListRecord for substring lists, but it
+// makes for confusing dumper output.
+TYPE_RECORD_ALIAS(LF_SUBSTR_LIST, 0x1604, StringList, ArgList)
+TYPE_RECORD(LF_STRING_ID, 0x1605, StringId)
+TYPE_RECORD(LF_UDT_SRC_LINE, 0x1606, UdtSourceLine)
+TYPE_RECORD(LF_UDT_MOD_SRC_LINE, 0x1607, UdtModSourceLine)
+
+
+TYPE_RECORD(LF_METHODLIST, 0x1206, MethodOverloadList)
+
+
+// 16 bit type records.
+CV_TYPE(LF_MODIFIER_16t, 0x0001)
+CV_TYPE(LF_POINTER_16t, 0x0002)
+CV_TYPE(LF_ARRAY_16t, 0x0003)
+CV_TYPE(LF_CLASS_16t, 0x0004)
+CV_TYPE(LF_STRUCTURE_16t, 0x0005)
+CV_TYPE(LF_UNION_16t, 0x0006)
+CV_TYPE(LF_ENUM_16t, 0x0007)
+CV_TYPE(LF_PROCEDURE_16t, 0x0008)
+CV_TYPE(LF_MFUNCTION_16t, 0x0009)
+CV_TYPE(LF_COBOL0_16t, 0x000b)
+CV_TYPE(LF_COBOL1, 0x000c)
+CV_TYPE(LF_BARRAY_16t, 0x000d)
+CV_TYPE(LF_LABEL, 0x000e)
+CV_TYPE(LF_NULLLEAF, 0x000f) // LF_NULL
+CV_TYPE(LF_NOTTRAN, 0x0010)
+CV_TYPE(LF_DIMARRAY_16t, 0x0011)
+CV_TYPE(LF_VFTPATH_16t, 0x0012)
+CV_TYPE(LF_PRECOMP_16t, 0x0013)
+CV_TYPE(LF_ENDPRECOMP, 0x0014)
+CV_TYPE(LF_OEM_16t, 0x0015)
+CV_TYPE(LF_TYPESERVER_ST, 0x0016)
+
+CV_TYPE(LF_SKIP_16t, 0x0200)
+CV_TYPE(LF_ARGLIST_16t, 0x0201)
+CV_TYPE(LF_DEFARG_16t, 0x0202)
+CV_TYPE(LF_LIST, 0x0203)
+CV_TYPE(LF_FIELDLIST_16t, 0x0204)
+CV_TYPE(LF_DERIVED_16t, 0x0205)
+CV_TYPE(LF_BITFIELD_16t, 0x0206)
+CV_TYPE(LF_METHODLIST_16t, 0x0207)
+CV_TYPE(LF_DIMCONU_16t, 0x0208)
+CV_TYPE(LF_DIMCONLU_16t, 0x0209)
+CV_TYPE(LF_DIMVARU_16t, 0x020a)
+CV_TYPE(LF_DIMVARLU_16t, 0x020b)
+CV_TYPE(LF_REFSYM, 0x020c)
+
+// 16 bit member types. Generally not length prefixed.
+CV_TYPE(LF_BCLASS_16t, 0x0400)
+CV_TYPE(LF_VBCLASS_16t, 0x0401)
+CV_TYPE(LF_IVBCLASS_16t, 0x0402)
+CV_TYPE(LF_ENUMERATE_ST, 0x0403)
+CV_TYPE(LF_FRIENDFCN_16t, 0x0404)
+CV_TYPE(LF_INDEX_16t, 0x0405)
+CV_TYPE(LF_MEMBER_16t, 0x0406)
+CV_TYPE(LF_STMEMBER_16t, 0x0407)
+CV_TYPE(LF_METHOD_16t, 0x0408)
+CV_TYPE(LF_NESTTYPE_16t, 0x0409)
+CV_TYPE(LF_VFUNCTAB_16t, 0x040a)
+CV_TYPE(LF_FRIENDCLS_16t, 0x040b)
+CV_TYPE(LF_ONEMETHOD_16t, 0x040c)
+CV_TYPE(LF_VFUNCOFF_16t, 0x040d)
+
+CV_TYPE(LF_TI16_MAX, 0x1000)
+
+CV_TYPE(LF_ARRAY_ST, 0x1003)
+CV_TYPE(LF_CLASS_ST, 0x1004)
+CV_TYPE(LF_STRUCTURE_ST, 0x1005)
+CV_TYPE(LF_UNION_ST, 0x1006)
+CV_TYPE(LF_ENUM_ST, 0x1007)
+CV_TYPE(LF_COBOL0, 0x100a)
+CV_TYPE(LF_BARRAY, 0x100b)
+CV_TYPE(LF_DIMARRAY_ST, 0x100c)
+CV_TYPE(LF_VFTPATH, 0x100d)
+CV_TYPE(LF_PRECOMP_ST, 0x100e)
+CV_TYPE(LF_OEM, 0x100f)
+CV_TYPE(LF_ALIAS_ST, 0x1010)
+CV_TYPE(LF_OEM2, 0x1011)
+
+CV_TYPE(LF_SKIP, 0x1200)
+CV_TYPE(LF_DEFARG_ST, 0x1202)
+CV_TYPE(LF_FIELDLIST, 0x1203)
+CV_TYPE(LF_DERIVED, 0x1204)
+CV_TYPE(LF_DIMCONU, 0x1207)
+CV_TYPE(LF_DIMCONLU, 0x1208)
+CV_TYPE(LF_DIMVARU, 0x1209)
+CV_TYPE(LF_DIMVARLU, 0x120a)
+
+// Member type records. These are generally not length prefixed, and appear
+// inside of a field list record.
+CV_TYPE(LF_FRIENDFCN_ST, 0x1403)
+CV_TYPE(LF_MEMBER_ST, 0x1405)
+CV_TYPE(LF_STMEMBER_ST, 0x1406)
+CV_TYPE(LF_METHOD_ST, 0x1407)
+CV_TYPE(LF_NESTTYPE_ST, 0x1408)
+CV_TYPE(LF_FRIENDCLS, 0x140a)
+CV_TYPE(LF_ONEMETHOD_ST, 0x140b)
+CV_TYPE(LF_VFUNCOFF, 0x140c)
+CV_TYPE(LF_NESTTYPEEX_ST, 0x140d)
+CV_TYPE(LF_MEMBERMODIFY_ST, 0x140e)
+CV_TYPE(LF_MANAGED_ST, 0x140f)
+
+CV_TYPE(LF_ST_MAX, 0x1500)
+CV_TYPE(LF_TYPESERVER, 0x1501)
+CV_TYPE(LF_DIMARRAY, 0x1508)
+CV_TYPE(LF_PRECOMP, 0x1509)
+CV_TYPE(LF_ALIAS, 0x150a)
+CV_TYPE(LF_DEFARG, 0x150b)
+CV_TYPE(LF_FRIENDFCN, 0x150c)
+CV_TYPE(LF_NESTTYPEEX, 0x1512)
+CV_TYPE(LF_MEMBERMODIFY, 0x1513)
+CV_TYPE(LF_MANAGED, 0x1514)
+CV_TYPE(LF_STRIDED_ARRAY, 0x1516)
+CV_TYPE(LF_HLSL, 0x1517)
+CV_TYPE(LF_MODIFIER_EX, 0x1518)
+CV_TYPE(LF_VECTOR, 0x151b)
+CV_TYPE(LF_MATRIX, 0x151c)
+
+// ID leaf records. Subsequent leaf types may be referenced from .debug$S.
+
+// Numeric leaf types. These are generally contained in other records, and not
+// encountered in the main type stream.
+
+CV_TYPE(LF_NUMERIC, 0x8000)
+CV_TYPE(LF_CHAR, 0x8000)
+CV_TYPE(LF_SHORT, 0x8001)
+CV_TYPE(LF_USHORT, 0x8002)
+CV_TYPE(LF_LONG, 0x8003)
+CV_TYPE(LF_ULONG, 0x8004)
+CV_TYPE(LF_REAL32, 0x8005)
+CV_TYPE(LF_REAL64, 0x8006)
+CV_TYPE(LF_REAL80, 0x8007)
+CV_TYPE(LF_REAL128, 0x8008)
+CV_TYPE(LF_QUADWORD, 0x8009)
+CV_TYPE(LF_UQUADWORD, 0x800a)
+CV_TYPE(LF_REAL48, 0x800b)
+CV_TYPE(LF_COMPLEX32, 0x800c)
+CV_TYPE(LF_COMPLEX64, 0x800d)
+CV_TYPE(LF_COMPLEX80, 0x800e)
+CV_TYPE(LF_COMPLEX128, 0x800f)
+CV_TYPE(LF_VARSTRING, 0x8010)
+CV_TYPE(LF_OCTWORD, 0x8017)
+CV_TYPE(LF_UOCTWORD, 0x8018)
+CV_TYPE(LF_DECIMAL, 0x8019)
+CV_TYPE(LF_DATE, 0x801a)
+CV_TYPE(LF_UTF8STRING, 0x801b)
+CV_TYPE(LF_REAL16, 0x801c)
+
+// Padding bytes. These are emitted into alignment bytes in the type stream.
+
+CV_TYPE(LF_PAD0, 0xf0)
+CV_TYPE(LF_PAD1, 0xf1)
+CV_TYPE(LF_PAD2, 0xf2)
+CV_TYPE(LF_PAD3, 0xf3)
+CV_TYPE(LF_PAD4, 0xf4)
+CV_TYPE(LF_PAD5, 0xf5)
+CV_TYPE(LF_PAD6, 0xf6)
+CV_TYPE(LF_PAD7, 0xf7)
+CV_TYPE(LF_PAD8, 0xf8)
+CV_TYPE(LF_PAD9, 0xf9)
+CV_TYPE(LF_PAD10, 0xfa)
+CV_TYPE(LF_PAD11, 0xfb)
+CV_TYPE(LF_PAD12, 0xfc)
+CV_TYPE(LF_PAD13, 0xfd)
+CV_TYPE(LF_PAD14, 0xfe)
+CV_TYPE(LF_PAD15, 0xff)
+
+#undef CV_TYPE
+#undef TYPE_RECORD
+#undef TYPE_RECORD_ALIAS
+#undef MEMBER_RECORD
+#undef MEMBER_RECORD_ALIAS
diff --git a/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h b/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h
new file mode 100644
index 0000000000000..af396c79d0741
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h
@@ -0,0 +1,26 @@
+//===- TypeStreamMerger.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H
+#define LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
+
+namespace llvm {
+namespace codeview {
+
+/// Merges one type stream into another. Returns true on success.
+bool mergeTypeStreams(TypeTableBuilder &DestStream, const CVTypeArray &Types);
+
+} // end namespace codeview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H
diff --git a/include/llvm/DebugInfo/CodeView/TypeSymbolEmitter.h b/include/llvm/DebugInfo/CodeView/TypeSymbolEmitter.h
index 9de110e8236fd..dfba83d62fcee 100644
--- a/include/llvm/DebugInfo/CodeView/TypeSymbolEmitter.h
+++ b/include/llvm/DebugInfo/CodeView/TypeSymbolEmitter.h
@@ -10,11 +10,12 @@
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESYMBOLEMITTER_H
#define LLVM_DEBUGINFO_CODEVIEW_TYPESYMBOLEMITTER_H
-#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
namespace llvm {
+class StringRef;
+
namespace codeview {
class TypeSymbolEmitter {
diff --git a/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h b/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h
index 2c950e8af792b..5b2aa61861470 100644
--- a/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h
+++ b/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h
@@ -10,13 +10,15 @@
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H
#define LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H
-#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/Support/Compiler.h"
namespace llvm {
+
+class StringRef;
+
namespace codeview {
class FieldListRecordBuilder;
@@ -38,20 +40,28 @@ public:
TypeIndex writeModifier(const ModifierRecord &Record);
TypeIndex writeProcedure(const ProcedureRecord &Record);
TypeIndex writeMemberFunction(const MemberFunctionRecord &Record);
- TypeIndex writeArgumentList(const ArgumentListRecord &Record);
- TypeIndex writeRecord(TypeRecordBuilder &builder);
+ TypeIndex writeArgList(const ArgListRecord &Record);
TypeIndex writePointer(const PointerRecord &Record);
- TypeIndex writePointerToMember(const PointerToMemberRecord &Record);
TypeIndex writeArray(const ArrayRecord &Record);
- TypeIndex writeAggregate(const AggregateRecord &Record);
+ TypeIndex writeClass(const ClassRecord &Record);
+ TypeIndex writeUnion(const UnionRecord &Record);
TypeIndex writeEnum(const EnumRecord &Record);
TypeIndex writeBitField(const BitFieldRecord &Record);
- TypeIndex writeVirtualTableShape(const VirtualTableShapeRecord &Record);
+ TypeIndex writeVFTableShape(const VFTableShapeRecord &Record);
+ TypeIndex writeStringId(const StringIdRecord &Record);
+ TypeIndex writeVFTable(const VFTableRecord &Record);
+ TypeIndex writeUdtSourceLine(const UdtSourceLineRecord &Record);
+ TypeIndex writeUdtModSourceLine(const UdtModSourceLineRecord &Record);
+ TypeIndex writeFuncId(const FuncIdRecord &Record);
+ TypeIndex writeMemberFuncId(const MemberFuncIdRecord &Record);
+ TypeIndex writeBuildInfo(const BuildInfoRecord &Record);
+ TypeIndex writeMethodOverloadList(const MethodOverloadListRecord &Record);
+ TypeIndex writeTypeServer2(const TypeServer2Record &Record);
TypeIndex writeFieldList(FieldListRecordBuilder &FieldList);
- TypeIndex writeMethodList(MethodListRecordBuilder &MethodList);
-private:
+ TypeIndex writeRecord(TypeRecordBuilder &builder);
+
virtual TypeIndex writeRecord(llvm::StringRef record) = 0;
};
}
diff --git a/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h b/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h
new file mode 100644
index 0000000000000..310847ec5d2dc
--- /dev/null
+++ b/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h
@@ -0,0 +1,63 @@
+//===- TypeVisitorCallbacks.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEVISITORCALLBACKS_H
+#define LLVM_DEBUGINFO_CODEVIEW_TYPEVISITORCALLBACKS_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace codeview {
+class TypeVisitorCallbacks {
+ friend class CVTypeVisitor;
+
+public:
+ virtual ~TypeVisitorCallbacks() {}
+
+ /// Action to take on unknown types. By default, they are ignored.
+ virtual Error visitUnknownType(const CVRecord<TypeLeafKind> &Record) {
+ return Error::success();
+ }
+ virtual Error visitUnknownMember(const CVRecord<TypeLeafKind> &Record) {
+ return Error::success();
+ }
+
+ /// Paired begin/end actions for all types. Receives all record data,
+ /// including the fixed-length record prefix.
+ virtual Error visitTypeBegin(const CVRecord<TypeLeafKind> &Record) {
+ return Error::success();
+ }
+ virtual Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) {
+ return Error::success();
+ }
+
+ virtual Error visitFieldListBegin(const CVRecord<TypeLeafKind> &Record) {
+ return Error::success();
+ }
+
+ virtual Error visitFieldListEnd(const CVRecord<TypeLeafKind> &Record) {
+ return Error::success();
+ }
+
+#define TYPE_RECORD(EnumName, EnumVal, Name) \
+ virtual Error visit##Name(Name##Record &Record) { return Error::success(); }
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ TYPE_RECORD(EnumName, EnumVal, Name)
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "TypeRecords.def"
+};
+}
+}
+
+#endif