diff options
Diffstat (limited to 'include/llvm/DebugInfo')
130 files changed, 7474 insertions, 696 deletions
diff --git a/include/llvm/DebugInfo/CodeView/ByteStream.h b/include/llvm/DebugInfo/CodeView/ByteStream.h new file mode 100644 index 000000000000..f398c93723e7 --- /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 000000000000..dba359fcbe82 --- /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 000000000000..32813d861d90 --- /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 000000000000..7c88956c984e --- /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 000000000000..930ac6930c24 --- /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 7728120d68de..1ee203b4f8fa 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 000000000000..69ff29aab6f1 --- /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 000000000000..021288e57618 --- /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 1ed62487aecc..75a075157d22 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 a7cdbdaac32f..975b503fe30b 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 df0a2e08a418..00bf03d417a2 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 5bfe2a068672..002f885c7c5a 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 000000000000..6affac801d4d --- /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 000000000000..6df230903712 --- /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 000000000000..84179f5f81f7 --- /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 000000000000..0b9349aac753 --- /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 000000000000..241aec457870 --- /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 000000000000..2f497c2c43f1 --- /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 000000000000..a4f244a32289 --- /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 000000000000..4d393d2ef790 --- /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 000000000000..30b0a40451cb --- /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 000000000000..648e40f55810 --- /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 000000000000..77e894fba4a9 --- /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 000000000000..a4965168c3db --- /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 000000000000..ca79ab076e5e --- /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 d3a541be4c62..c2ebf3848892 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 21755f5d9b09..42751fbd4af1 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 1f48cf70666d..eb7993baab89 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 000000000000..0959f4bf19c7 --- /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 000000000000..af396c79d074 --- /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 9de110e8236f..dfba83d62fce 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 2c950e8af792..5b2aa6186147 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 000000000000..310847ec5d2d --- /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 diff --git a/include/llvm/DebugInfo/DIContext.h b/include/llvm/DebugInfo/DIContext.h index 6659a97a042b..2f88371979ea 100644 --- a/include/llvm/DebugInfo/DIContext.h +++ b/include/llvm/DebugInfo/DIContext.h @@ -15,10 +15,8 @@ #ifndef LLVM_DEBUGINFO_DICONTEXT_H #define LLVM_DEBUGINFO_DICONTEXT_H -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Object/RelocVisitor.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DataTypes.h" #include <string> @@ -140,7 +138,8 @@ public: DIContext(DIContextKind K) : Kind(K) {} virtual ~DIContext() {} - virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) = 0; + virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All, + bool DumpEH = false) = 0; virtual DILineInfo getLineInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; diff --git a/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h b/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h index bae3154b3b5f..bba3abe6e9e9 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h @@ -19,10 +19,10 @@ public: DWARFCompileUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, StringRef LS, bool LE, - const DWARFUnitSectionBase &UnitSection, + bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *Entry) - : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, UnitSection, - Entry) {} + : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + UnitSection, Entry) {} void dump(raw_ostream &OS); static const DWARFSectionKind Section = DW_SECT_INFO; // VTable anchor. diff --git a/include/llvm/DebugInfo/DWARF/DWARFContext.h b/include/llvm/DebugInfo/DWARF/DWARFContext.h index c91012bc9a24..741a31cb582b 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ b/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -22,7 +22,6 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" -#include <vector> namespace llvm { @@ -40,7 +39,7 @@ typedef DenseMap<uint64_t, std::pair<uint8_t, int64_t> > RelocAddrMap; class DWARFContext : public DIContext { DWARFUnitSection<DWARFCompileUnit> CUs; - std::vector<DWARFUnitSection<DWARFTypeUnit>> TUs; + std::deque<DWARFUnitSection<DWARFTypeUnit>> TUs; std::unique_ptr<DWARFUnitIndex> CUIndex; std::unique_ptr<DWARFUnitIndex> TUIndex; std::unique_ptr<DWARFDebugAbbrev> Abbrev; @@ -48,10 +47,11 @@ class DWARFContext : public DIContext { std::unique_ptr<DWARFDebugAranges> Aranges; std::unique_ptr<DWARFDebugLine> Line; std::unique_ptr<DWARFDebugFrame> DebugFrame; + std::unique_ptr<DWARFDebugFrame> EHFrame; std::unique_ptr<DWARFDebugMacro> Macro; DWARFUnitSection<DWARFCompileUnit> DWOCUs; - std::vector<DWARFUnitSection<DWARFTypeUnit>> DWOTUs; + std::deque<DWARFUnitSection<DWARFTypeUnit>> DWOTUs; std::unique_ptr<DWARFDebugAbbrev> AbbrevDWO; std::unique_ptr<DWARFDebugLocDWO> LocDWO; @@ -81,11 +81,12 @@ public: return DICtx->getKind() == CK_DWARF; } - void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) override; + void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All, + bool DumpEH = false) override; typedef DWARFUnitSection<DWARFCompileUnit>::iterator_range cu_iterator_range; typedef DWARFUnitSection<DWARFTypeUnit>::iterator_range tu_iterator_range; - typedef iterator_range<std::vector<DWARFUnitSection<DWARFTypeUnit>>::iterator> tu_section_iterator_range; + typedef iterator_range<decltype(TUs)::iterator> tu_section_iterator_range; /// Get compile units in this context. cu_iterator_range compile_units() { @@ -168,6 +169,9 @@ public: /// Get a pointer to the parsed frame information object. const DWARFDebugFrame *getDebugFrame(); + /// Get a pointer to the parsed eh frame information object. + const DWARFDebugFrame *getEHFrame(); + /// Get a pointer to the parsed DebugMacro object. const DWARFDebugMacro *getDebugMacro(); @@ -191,6 +195,7 @@ public: virtual const DWARFSection &getLocSection() = 0; virtual StringRef getARangeSection() = 0; virtual StringRef getDebugFrameSection() = 0; + virtual StringRef getEHFrameSection() = 0; virtual const DWARFSection &getLineSection() = 0; virtual StringRef getStringSection() = 0; virtual StringRef getRangeSection() = 0; @@ -242,6 +247,7 @@ class DWARFContextInMemory : public DWARFContext { DWARFSection LocSection; StringRef ARangeSection; StringRef DebugFrameSection; + StringRef EHFrameSection; DWARFSection LineSection; StringRef StringSection; StringRef RangeSection; @@ -281,6 +287,7 @@ public: const DWARFSection &getLocSection() override { return LocSection; } StringRef getARangeSection() override { return ARangeSection; } StringRef getDebugFrameSection() override { return DebugFrameSection; } + StringRef getEHFrameSection() override { return EHFrameSection; } const DWARFSection &getLineSection() override { return LineSection; } StringRef getStringSection() override { return StringSection; } StringRef getRangeSection() override { return RangeSection; } diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h b/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h index 21142089da6b..67c4a2bb3e67 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h @@ -11,7 +11,6 @@ #define LLVM_LIB_DEBUGINFO_DWARFDEBUGABBREV_H #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" -#include <list> #include <map> #include <vector> diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h index be925cbe7519..cd76c909ddae 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h @@ -19,11 +19,13 @@ namespace llvm { class FrameEntry; -/// \brief A parsed .debug_frame section +/// \brief A parsed .debug_frame or .eh_frame section /// class DWARFDebugFrame { + // True if this is parsing an eh_frame section. + bool IsEH; public: - DWARFDebugFrame(); + DWARFDebugFrame(bool IsEH); ~DWARFDebugFrame(); /// \brief Dump the section data into the given stream. diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h b/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h index f7910962a03f..731c521b9edb 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h @@ -11,7 +11,6 @@ #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGMACRO_H
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Dwarf.h"
diff --git a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h index 3c32a3e5b794..b2f750dd7945 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -10,12 +10,12 @@ #ifndef LLVM_DEBUGINFO_DWARFFORMVALUE_H #define LLVM_DEBUGINFO_DWARFFORMVALUE_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/DataExtractor.h" namespace llvm { +template <typename T> class ArrayRef; class DWARFUnit; class raw_ostream; diff --git a/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h b/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h index 894a88dce440..a697edd32072 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h @@ -21,11 +21,11 @@ private: public: DWARFTypeUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, - StringRef SOS, StringRef AOS, StringRef LS, bool LE, + StringRef SOS, StringRef AOS, StringRef LS, bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *Entry) - : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, UnitSection, - Entry) {} + : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + UnitSection, Entry) {} uint32_t getHeaderSize() const override { return DWARFUnit::getHeaderSize() + 12; } diff --git a/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/include/llvm/DebugInfo/DWARF/DWARFUnit.h index 681b2aa19a79..9c3fe3be6aa6 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -47,7 +47,7 @@ protected: virtual void parseImpl(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, StringRef LS, - bool isLittleEndian) = 0; + bool isLittleEndian, bool isDWO) = 0; ~DWARFUnitSectionBase() = default; }; @@ -59,13 +59,9 @@ const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context, template<typename UnitType> class DWARFUnitSection final : public SmallVector<std::unique_ptr<UnitType>, 1>, public DWARFUnitSectionBase { - bool Parsed; + bool Parsed = false; public: - DWARFUnitSection() : Parsed(false) {} - DWARFUnitSection(DWARFUnitSection &&DUS) : - SmallVector<std::unique_ptr<UnitType>, 1>(std::move(DUS)), Parsed(DUS.Parsed) {} - typedef llvm::SmallVectorImpl<std::unique_ptr<UnitType>> UnitVector; typedef typename UnitVector::iterator iterator; typedef llvm::iterator_range<typename UnitVector::iterator> iterator_range; @@ -84,7 +80,8 @@ public: private: void parseImpl(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, - StringRef SOS, StringRef AOS, StringRef LS, bool LE) override { + StringRef SOS, StringRef AOS, StringRef LS, bool LE, + bool IsDWO) override { if (Parsed) return; const auto &Index = getDWARFUnitIndex(Context, UnitType::Section); @@ -92,7 +89,7 @@ private: uint32_t Offset = 0; while (Data.isValidOffset(Offset)) { auto U = llvm::make_unique<UnitType>(Context, Section, DA, RS, SS, SOS, - AOS, LS, LE, *this, + AOS, LS, LE, IsDWO, *this, Index.getFromOffset(Offset)); if (!U->extract(Data, &Offset)) break; @@ -117,6 +114,7 @@ class DWARFUnit { StringRef AddrOffsetSection; uint32_t AddrOffsetSectionBase; bool isLittleEndian; + bool isDWO; const DWARFUnitSectionBase &UnitSection; uint32_t Offset; @@ -148,7 +146,7 @@ protected: public: DWARFUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, - StringRef SOS, StringRef AOS, StringRef LS, bool LE, + StringRef SOS, StringRef AOS, StringRef LS, bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *IndexEntry = nullptr); @@ -249,7 +247,7 @@ public: /// \brief Return the DIE object for a given offset inside the /// unit's DIE vector. /// - /// The unit needs to have his DIEs extracted for this method to work. + /// The unit needs to have its DIEs extracted for this method to work. const DWARFDebugInfoEntryMinimal *getDIEForOffset(uint32_t Offset) const { assert(!DieArray.empty()); auto it = std::lower_bound( diff --git a/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h b/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h index a85c2f9f0a23..9f051cd7081c 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h +++ b/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h @@ -10,6 +10,7 @@ #ifndef LLVM_LIB_DEBUGINFO_DWARFUNITINDEX_H #define LLVM_LIB_DEBUGINFO_DWARFUNITINDEX_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -56,6 +57,10 @@ public: public: const SectionContribution *getOffset(DWARFSectionKind Sec) const; const SectionContribution *getOffset() const; + const SectionContribution *getOffsets() const { + return Contributions.get(); + } + uint64_t getSignature() const { return Signature; } }; private: @@ -75,6 +80,12 @@ public: : InfoColumnKind(InfoColumnKind) {} void dump(raw_ostream &OS) const; const Entry *getFromOffset(uint32_t Offset) const; + ArrayRef<DWARFSectionKind> getColumnKinds() const { + return makeArrayRef(ColumnKinds.get(), Header.NumColumns); + } + ArrayRef<Entry> getRows() const { + return makeArrayRef(Rows.get(), Header.NumBuckets); + } }; } diff --git a/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h b/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h index b5fa8c33414d..50f5c40bcac9 100644 --- a/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h +++ b/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h @@ -15,6 +15,7 @@ #include <memory> namespace llvm { +namespace pdb { template <typename ChildType> class ConcreteSymbolEnumerator : public IPDBEnumChildren<ChildType> { @@ -55,5 +56,6 @@ private: std::unique_ptr<IPDBEnumSymbols> Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIADataStream.h b/include/llvm/DebugInfo/PDB/DIA/DIADataStream.h index 7b2bc146b32d..930bea6060b2 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIADataStream.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIADataStream.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBDataStream.h" namespace llvm { +namespace pdb { class DIADataStream : public IPDBDataStream { public: explicit DIADataStream(CComPtr<IDiaEnumDebugStreamData> DiaStreamData); @@ -29,5 +30,6 @@ private: CComPtr<IDiaEnumDebugStreamData> StreamData; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h index 375bcdd7e3bd..941e16a35fac 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" namespace llvm { +namespace pdb { class IPDBDataStream; @@ -31,5 +32,6 @@ private: CComPtr<IDiaEnumDebugStreams> Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h index 4cc85eda477f..106b84cecfff 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h @@ -14,7 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" namespace llvm { - +namespace pdb { class IPDBLineNumber; class DIAEnumLineNumbers : public IPDBEnumChildren<IPDBLineNumber> { @@ -31,5 +31,6 @@ private: CComPtr<IDiaEnumLineNumbers> Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h index 88625f64e49e..6c00d6a5e29d 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h @@ -14,7 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" namespace llvm { - +namespace pdb { class DIASession; class DIAEnumSourceFiles : public IPDBEnumChildren<IPDBSourceFile> { @@ -33,5 +33,6 @@ private: CComPtr<IDiaEnumSourceFiles> Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h index fe343f778aad..b206ff59a6a4 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h @@ -14,7 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" namespace llvm { - +namespace pdb { class DIASession; class DIAEnumSymbols : public IPDBEnumChildren<PDBSymbol> { @@ -33,5 +33,6 @@ private: CComPtr<IDiaEnumSymbols> Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAError.h b/include/llvm/DebugInfo/PDB/DIA/DIAError.h new file mode 100644 index 000000000000..f198d07e99d4 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/DIA/DIAError.h @@ -0,0 +1,46 @@ +//===- DIAError.h - Error extensions for PDB DIA implementation -*- 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_DIA_DIAERROR_H +#define LLVM_DEBUGINFO_PDB_DIA_DIAERROR_H + +#include "llvm/Support/Error.h" + +#include <string> + +namespace llvm { +namespace pdb { +enum class dia_error_code { + unspecified = 1, + could_not_create_impl, + invalid_file_format, + invalid_parameter, + already_loaded, + debug_info_mismatch, +}; + +/// Base class for errors originating in DIA SDK, e.g. COM calls +class DIAError : public ErrorInfo<DIAError> { +public: + static char ID; + DIAError(dia_error_code C); + DIAError(const std::string &Context); + DIAError(dia_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; + dia_error_code Code; +}; +} +} +#endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIALineNumber.h b/include/llvm/DebugInfo/PDB/DIA/DIALineNumber.h index 5950a0d3835f..a59e3a19c8c2 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIALineNumber.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIALineNumber.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBLineNumber.h" namespace llvm { +namespace pdb { class DIALineNumber : public IPDBLineNumber { public: explicit DIALineNumber(CComPtr<IDiaLineNumber> DiaLineNumber); @@ -35,5 +36,5 @@ private: CComPtr<IDiaLineNumber> LineNumber; }; } - +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h b/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h index 9308b8e82657..1e40c46f8a27 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" namespace llvm { +namespace pdb { class DIASession; class DIARawSymbol : public IPDBRawSymbol { public: @@ -58,7 +59,7 @@ public: uint32_t getLiveRangeStartAddressOffset() const override; uint32_t getLiveRangeStartAddressSection() const override; uint32_t getLiveRangeStartRelativeVirtualAddress() const override; - PDB_RegisterId getLocalBasePointerRegisterId() const override; + codeview::RegisterId getLocalBasePointerRegisterId() const override; uint32_t getLowerBoundId() const override; uint32_t getMemorySpaceKind() const override; std::string getName() const override; @@ -73,7 +74,7 @@ public: uint32_t getOffsetInUdt() const override; PDB_Cpu getPlatform() const override; uint32_t getRank() const override; - PDB_RegisterId getRegisterId() const override; + codeview::RegisterId getRegisterId() const override; uint32_t getRegisterType() const override; uint32_t getRelativeVirtualAddress() const override; uint32_t getSamplerSlot() const override; @@ -109,7 +110,7 @@ public: int32_t getVirtualBasePointerOffset() const override; PDB_LocType getLocationType() const override; PDB_Machine getMachineType() const override; - PDB_ThunkOrdinal getThunkOrdinal() const override; + codeview::ThunkOrdinal getThunkOrdinal() const override; uint64_t getLength() const override; uint64_t getLiveRangeLength() const override; uint64_t getVirtualAddress() const override; @@ -202,5 +203,6 @@ private: CComPtr<IDiaSymbol> Symbol; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIASession.h b/include/llvm/DebugInfo/PDB/DIA/DIASession.h index 9a8600fb85ec..3f5818631e7b 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIASession.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIASession.h @@ -11,18 +11,23 @@ #define LLVM_DEBUGINFO_PDB_DIA_DIASESSION_H #include "DIASupport.h" -#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/Support/Error.h" + +#include <system_error> namespace llvm { +class StringRef; + +namespace pdb { class DIASession : public IPDBSession { public: explicit DIASession(CComPtr<IDiaSession> DiaSession); - static PDB_ErrorCode createFromPdb(StringRef Path, - std::unique_ptr<IPDBSession> &Session); - static PDB_ErrorCode createFromExe(StringRef Path, - std::unique_ptr<IPDBSession> &Session); + static Error createFromPdb(StringRef Path, + std::unique_ptr<IPDBSession> &Session); + static Error createFromExe(StringRef Path, + std::unique_ptr<IPDBSession> &Session); uint64_t getLoadAddress() const override; void setLoadAddress(uint64_t Address) override; @@ -33,8 +38,24 @@ public: findSymbolByAddress(uint64_t Address, PDB_SymType Type) const override; std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbers(const PDBSymbolCompiland &Compiland, + const IPDBSourceFile &File) const override; + std::unique_ptr<IPDBEnumLineNumbers> findLineNumbersByAddress(uint64_t Address, uint32_t Length) const override; + std::unique_ptr<IPDBEnumSourceFiles> + findSourceFiles(const PDBSymbolCompiland *Compiland, llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<IPDBSourceFile> + findOneSourceFile(const PDBSymbolCompiland *Compiland, + llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> + findCompilandsForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<PDBSymbolCompiland> + findOneCompilandForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; std::unique_ptr<IPDBEnumSourceFiles> getAllSourceFiles() const override; std::unique_ptr<IPDBEnumSourceFiles> getSourceFilesForCompiland( const PDBSymbolCompiland &Compiland) const override; @@ -47,5 +68,5 @@ private: CComPtr<IDiaSession> Session; }; } - +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIASourceFile.h b/include/llvm/DebugInfo/PDB/DIA/DIASourceFile.h index c424e27493c1..1088ea54981c 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIASourceFile.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIASourceFile.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" namespace llvm { +namespace pdb { class DIASession; class DIASourceFile : public IPDBSourceFile { @@ -25,12 +26,16 @@ public: uint32_t getUniqueId() const override; std::string getChecksum() const override; PDB_Checksum getChecksumType() const override; - std::unique_ptr<IPDBEnumSymbols> getCompilands() const override; + std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> + getCompilands() const override; + + CComPtr<IDiaSourceFile> getDiaFile() const { return SourceFile; } private: const DIASession &Session; CComPtr<IDiaSourceFile> SourceFile; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIASupport.h b/include/llvm/DebugInfo/PDB/DIA/DIASupport.h index 407a34551cc7..3b4a348289df 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIASupport.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIASupport.h @@ -22,6 +22,14 @@ #define NOMINMAX #endif +// llvm/Support/Debug.h unconditionally #defines DEBUG as a macro. +// DIA headers #define it if it is not already defined, so we have +// an order of includes problem. The real fix is to make LLVM use +// something less generic than DEBUG, such as LLVM_DEBUG(), but it's +// fairly prevalent. So for now, we save the definition state and +// restore it. +#pragma push_macro("DEBUG") + // atlbase.h has to come before windows.h #include <atlbase.h> #include <windows.h> @@ -29,5 +37,8 @@ // DIA headers must come after windows headers. #include <cvconst.h> #include <dia2.h> +#include <diacreate.h> + +#pragma pop_macro("DEBUG") #endif // LLVM_DEBUGINFO_PDB_DIA_DIASUPPORT_H diff --git a/include/llvm/DebugInfo/PDB/GenericError.h b/include/llvm/DebugInfo/PDB/GenericError.h new file mode 100644 index 000000000000..959c26161044 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/GenericError.h @@ -0,0 +1,42 @@ +//===- Error.h - system_error extensions for PDB ----------------*- 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_ERROR_H +#define LLVM_DEBUGINFO_PDB_ERROR_H + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { + +enum class generic_error_code { + invalid_path = 1, + dia_sdk_not_present, + unspecified, +}; + +/// Base class for errors originating when parsing raw PDB files +class GenericError : public ErrorInfo<GenericError> { +public: + static char ID; + GenericError(generic_error_code C); + GenericError(const std::string &Context); + GenericError(generic_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; + generic_error_code Code; +}; +} +} +#endif diff --git a/include/llvm/DebugInfo/PDB/IPDBDataStream.h b/include/llvm/DebugInfo/PDB/IPDBDataStream.h index 808a0f3ec3a9..9594dc1591a7 100644 --- a/include/llvm/DebugInfo/PDB/IPDBDataStream.h +++ b/include/llvm/DebugInfo/PDB/IPDBDataStream.h @@ -15,6 +15,7 @@ #include "llvm/ADT/SmallVector.h" namespace llvm { +namespace pdb { /// IPDBDataStream defines an interface used to represent a stream consisting /// of a name and a series of records whose formats depend on the particular @@ -33,5 +34,6 @@ public: virtual IPDBDataStream *clone() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h b/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h index 645ac96e23a5..8e9f6f883679 100644 --- a/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h +++ b/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h @@ -14,6 +14,7 @@ #include <memory> namespace llvm { +namespace pdb { template <typename ChildType> class IPDBEnumChildren { public: @@ -29,5 +30,6 @@ public: virtual MyType *clone() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBLineNumber.h b/include/llvm/DebugInfo/PDB/IPDBLineNumber.h index 92cd58d86649..e20080f2fbfc 100644 --- a/include/llvm/DebugInfo/PDB/IPDBLineNumber.h +++ b/include/llvm/DebugInfo/PDB/IPDBLineNumber.h @@ -13,7 +13,7 @@ #include "PDBTypes.h" namespace llvm { - +namespace pdb { class IPDBLineNumber { public: virtual ~IPDBLineNumber(); @@ -32,5 +32,6 @@ public: virtual bool isStatement() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h b/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h index 139bff56fd5d..49866b8bb2f2 100644 --- a/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h +++ b/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h @@ -13,12 +13,14 @@ #include "PDBTypes.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" #include <memory> namespace llvm { - class raw_ostream; +namespace pdb { + /// IPDBRawSymbol defines an interface used to represent an arbitrary symbol. /// It exposes a monolithic interface consisting of accessors for the union of /// all properties that are valid for any symbol type. This interface is then @@ -66,7 +68,7 @@ public: virtual uint32_t getLiveRangeStartAddressOffset() const = 0; virtual uint32_t getLiveRangeStartAddressSection() const = 0; virtual uint32_t getLiveRangeStartRelativeVirtualAddress() const = 0; - virtual PDB_RegisterId getLocalBasePointerRegisterId() const = 0; + virtual codeview::RegisterId getLocalBasePointerRegisterId() const = 0; virtual uint32_t getLowerBoundId() const = 0; virtual uint32_t getMemorySpaceKind() const = 0; virtual std::string getName() const = 0; @@ -81,7 +83,7 @@ public: virtual uint32_t getOffsetInUdt() const = 0; virtual PDB_Cpu getPlatform() const = 0; virtual uint32_t getRank() const = 0; - virtual PDB_RegisterId getRegisterId() const = 0; + virtual codeview::RegisterId getRegisterId() const = 0; virtual uint32_t getRegisterType() const = 0; virtual uint32_t getRelativeVirtualAddress() const = 0; virtual uint32_t getSamplerSlot() const = 0; @@ -117,7 +119,7 @@ public: virtual int32_t getVirtualBasePointerOffset() const = 0; virtual PDB_LocType getLocationType() const = 0; virtual PDB_Machine getMachineType() const = 0; - virtual PDB_ThunkOrdinal getThunkOrdinal() const = 0; + virtual codeview::ThunkOrdinal getThunkOrdinal() const = 0; virtual uint64_t getLength() const = 0; virtual uint64_t getLiveRangeLength() const = 0; virtual uint64_t getVirtualAddress() const = 0; @@ -206,6 +208,7 @@ public: virtual std::string getUnused() const = 0; }; +} // namespace pdb } // namespace llvm #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBSession.h b/include/llvm/DebugInfo/PDB/IPDBSession.h index a130a38a6538..3d2c37eff2e3 100644 --- a/include/llvm/DebugInfo/PDB/IPDBSession.h +++ b/include/llvm/DebugInfo/PDB/IPDBSession.h @@ -11,11 +11,12 @@ #define LLVM_DEBUGINFO_PDB_IPDBSESSION_H #include "PDBTypes.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include <memory> namespace llvm { - +namespace pdb { class PDBSymbolCompiland; class PDBSymbolExe; @@ -45,9 +46,27 @@ public: virtual std::unique_ptr<PDBSymbol> findSymbolByAddress(uint64_t Address, PDB_SymType Type) const = 0; + + virtual std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbers(const PDBSymbolCompiland &Compiland, + const IPDBSourceFile &File) const = 0; virtual std::unique_ptr<IPDBEnumLineNumbers> findLineNumbersByAddress(uint64_t Address, uint32_t Length) const = 0; + virtual std::unique_ptr<IPDBEnumSourceFiles> + findSourceFiles(const PDBSymbolCompiland *Compiland, llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const = 0; + virtual std::unique_ptr<IPDBSourceFile> + findOneSourceFile(const PDBSymbolCompiland *Compiland, + llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const = 0; + virtual std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> + findCompilandsForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const = 0; + virtual std::unique_ptr<PDBSymbolCompiland> + findOneCompilandForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const = 0; + virtual std::unique_ptr<IPDBEnumSourceFiles> getAllSourceFiles() const = 0; virtual std::unique_ptr<IPDBEnumSourceFiles> getSourceFilesForCompiland(const PDBSymbolCompiland &Compiland) const = 0; @@ -57,5 +76,6 @@ public: virtual std::unique_ptr<IPDBEnumDataStreams> getDebugStreams() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBSourceFile.h b/include/llvm/DebugInfo/PDB/IPDBSourceFile.h index 55000eff02f0..3676c4030b13 100644 --- a/include/llvm/DebugInfo/PDB/IPDBSourceFile.h +++ b/include/llvm/DebugInfo/PDB/IPDBSourceFile.h @@ -15,9 +15,10 @@ #include <string> namespace llvm { - class raw_ostream; +namespace pdb { + /// IPDBSourceFile defines an interface used to represent source files whose /// information are stored in the PDB. class IPDBSourceFile { @@ -30,8 +31,10 @@ public: virtual uint32_t getUniqueId() const = 0; virtual std::string getChecksum() const = 0; virtual PDB_Checksum getChecksumType() const = 0; - virtual std::unique_ptr<IPDBEnumSymbols> getCompilands() const = 0; + virtual std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> + getCompilands() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDB.h b/include/llvm/DebugInfo/PDB/PDB.h index 5df3be85e381..1f5a066b9a1b 100644 --- a/include/llvm/DebugInfo/PDB/PDB.h +++ b/include/llvm/DebugInfo/PDB/PDB.h @@ -11,16 +11,20 @@ #define LLVM_DEBUGINFO_PDB_PDB_H #include "PDBTypes.h" +#include "llvm/Support/Error.h" #include <memory> +#include <system_error> namespace llvm { class StringRef; -PDB_ErrorCode loadDataForPDB(PDB_ReaderType Type, StringRef Path, - std::unique_ptr<IPDBSession> &Session); +namespace pdb { -PDB_ErrorCode loadDataForEXE(PDB_ReaderType Type, StringRef Path, - std::unique_ptr<IPDBSession> &Session); -} +Error loadDataForPDB(PDB_ReaderType Type, StringRef Path, + std::unique_ptr<IPDBSession> &Session); +Error loadDataForEXE(PDB_ReaderType Type, StringRef Path, + std::unique_ptr<IPDBSession> &Session); +} +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDBContext.h b/include/llvm/DebugInfo/PDB/PDBContext.h index 9404a5922449..836e39248438 100644 --- a/include/llvm/DebugInfo/PDB/PDBContext.h +++ b/include/llvm/DebugInfo/PDB/PDBContext.h @@ -17,43 +17,46 @@ namespace llvm { namespace object { class COFFObjectFile; -} - -/// PDBContext -/// This data structure is the top level entity that deals with PDB debug -/// information parsing. This data structure exists only when there is a -/// need for a transparent interface to different debug information formats -/// (e.g. PDB and DWARF). More control and power over the debug information -/// access can be had by using the PDB interfaces directly. -class PDBContext : public DIContext { - - PDBContext(PDBContext &) = delete; - PDBContext &operator=(PDBContext &) = delete; - -public: - PDBContext(const object::COFFObjectFile &Object, - std::unique_ptr<IPDBSession> PDBSession); - - static bool classof(const DIContext *DICtx) { - return DICtx->getKind() == CK_PDB; } - void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) override; - - DILineInfo getLineInfoForAddress( - uint64_t Address, - DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; - DILineInfoTable getLineInfoForAddressRange( - uint64_t Address, uint64_t Size, - DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; - DIInliningInfo getInliningInfoForAddress( - uint64_t Address, - DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; - -private: - std::string getFunctionName(uint64_t Address, DINameKind NameKind) const; - std::unique_ptr<IPDBSession> Session; -}; + namespace pdb { + /// PDBContext + /// This data structure is the top level entity that deals with PDB debug + /// information parsing. This data structure exists only when there is a + /// need for a transparent interface to different debug information formats + /// (e.g. PDB and DWARF). More control and power over the debug information + /// access can be had by using the PDB interfaces directly. + class PDBContext : public DIContext { + + PDBContext(PDBContext &) = delete; + PDBContext &operator=(PDBContext &) = delete; + + public: + PDBContext(const object::COFFObjectFile &Object, + std::unique_ptr<IPDBSession> PDBSession); + + static bool classof(const DIContext *DICtx) { + return DICtx->getKind() == CK_PDB; + } + + void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All, + bool DumpEH = false) override; + + DILineInfo getLineInfoForAddress( + uint64_t Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; + DILineInfoTable getLineInfoForAddressRange( + uint64_t Address, uint64_t Size, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; + DIInliningInfo getInliningInfoForAddress( + uint64_t Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; + + private: + std::string getFunctionName(uint64_t Address, DINameKind NameKind) const; + std::unique_ptr<IPDBSession> Session; + }; + } } #endif diff --git a/include/llvm/DebugInfo/PDB/PDBExtras.h b/include/llvm/DebugInfo/PDB/PDBExtras.h index 48ce1c127196..5a7422d9e9e4 100644 --- a/include/llvm/DebugInfo/PDB/PDBExtras.h +++ b/include/llvm/DebugInfo/PDB/PDBExtras.h @@ -11,28 +11,33 @@ #define LLVM_DEBUGINFO_PDB_PDBEXTRAS_H #include "PDBTypes.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/Support/raw_ostream.h" #include <unordered_map> namespace llvm { + +namespace pdb { typedef std::unordered_map<PDB_SymType, int> TagStats; raw_ostream &operator<<(raw_ostream &OS, const PDB_VariantType &Value); raw_ostream &operator<<(raw_ostream &OS, const PDB_CallingConv &Conv); raw_ostream &operator<<(raw_ostream &OS, const PDB_DataKind &Data); -raw_ostream &operator<<(raw_ostream &OS, const PDB_RegisterId &Reg); +raw_ostream &operator<<(raw_ostream &OS, const codeview::RegisterId &Reg); raw_ostream &operator<<(raw_ostream &OS, const PDB_LocType &Loc); -raw_ostream &operator<<(raw_ostream &OS, const PDB_ThunkOrdinal &Thunk); +raw_ostream &operator<<(raw_ostream &OS, const codeview::ThunkOrdinal &Thunk); raw_ostream &operator<<(raw_ostream &OS, const PDB_Checksum &Checksum); raw_ostream &operator<<(raw_ostream &OS, const PDB_Lang &Lang); raw_ostream &operator<<(raw_ostream &OS, const PDB_SymType &Tag); raw_ostream &operator<<(raw_ostream &OS, const PDB_MemberAccess &Access); raw_ostream &operator<<(raw_ostream &OS, const PDB_UdtType &Type); raw_ostream &operator<<(raw_ostream &OS, const PDB_UniqueId &Id); +raw_ostream &operator<<(raw_ostream &OS, const PDB_Machine &Machine); raw_ostream &operator<<(raw_ostream &OS, const Variant &Value); raw_ostream &operator<<(raw_ostream &OS, const VersionInfo &Version); raw_ostream &operator<<(raw_ostream &OS, const TagStats &Stats); } +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDBSymDumper.h b/include/llvm/DebugInfo/PDB/PDBSymDumper.h index 65110f39366f..095c33cfe8b5 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymDumper.h +++ b/include/llvm/DebugInfo/PDB/PDBSymDumper.h @@ -15,6 +15,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymDumper { public: @@ -57,5 +58,6 @@ private: bool RequireImpl; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDBSymbol.h b/include/llvm/DebugInfo/PDB/PDBSymbol.h index 4360c5431e69..bf5118806540 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbol.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbol.h @@ -15,9 +15,7 @@ #include "PDBExtras.h" #include "PDBTypes.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" -#include <unordered_map> #define FORWARD_SYMBOL_METHOD(MethodName) \ auto MethodName() const->decltype(RawSymbol->MethodName()) { \ @@ -26,9 +24,12 @@ namespace llvm { -class IPDBRawSymbol; +class StringRef; class raw_ostream; +namespace pdb { +class IPDBRawSymbol; + #define DECLARE_PDB_SYMBOL_CONCRETE_TYPE(TagValue) \ static const PDB_SymType Tag = TagValue; \ static bool classof(const PDBSymbol *S) { return S->getSymTag() == Tag; } @@ -41,7 +42,8 @@ class raw_ostream; /// https://msdn.microsoft.com/en-us/library/370hs6k4.aspx class PDBSymbol { protected: - PDBSymbol(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol); + PDBSymbol(const IPDBSession &PDBSession, + std::unique_ptr<IPDBRawSymbol> Symbol); public: static std::unique_ptr<PDBSymbol> @@ -57,6 +59,7 @@ public: void defaultDump(raw_ostream &OS, int Indent) const; PDB_SymType getSymTag() const; + uint32_t getSymIndexId() const; template <typename T> std::unique_ptr<T> findOneChild() const { auto Enumerator(findAllChildren<T>()); @@ -93,5 +96,6 @@ protected: }; } // namespace llvm +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolAnnotation.h b/include/llvm/DebugInfo/PDB/PDBSymbolAnnotation.h index c055dd7f3d49..3169146e5b12 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolAnnotation.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolAnnotation.h @@ -11,11 +11,11 @@ #include "PDBSymbol.h" #include "PDBTypes.h" -#include <string> namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolAnnotation : public PDBSymbol { public: @@ -30,10 +30,10 @@ public: FORWARD_SYMBOL_METHOD(getAddressSection) FORWARD_SYMBOL_METHOD(getDataKind) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) - FORWARD_SYMBOL_METHOD(getSymIndexId) // FORWARD_SYMBOL_METHOD(getValue) FORWARD_SYMBOL_METHOD(getVirtualAddress) }; } +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLANNOTATION_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h b/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h index 2ca12501d9f6..d0ff62ca7c3f 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h @@ -11,12 +11,13 @@ #include "PDBSymbol.h" #include "PDBTypes.h" -#include <string> namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolBlock : public PDBSymbol { public: PDBSymbolBlock(const IPDBSession &PDBSession, @@ -33,9 +34,9 @@ public: FORWARD_SYMBOL_METHOD(getLocationType) FORWARD_SYMBOL_METHOD(getName) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getVirtualAddress) }; } +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLBLOCK_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h b/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h index f8c796ae5bdc..f1983b3f7bf5 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h @@ -17,6 +17,8 @@ namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolCompiland : public PDBSymbol { public: PDBSymbolCompiland(const IPDBSession &PDBSession, @@ -30,9 +32,10 @@ public: FORWARD_SYMBOL_METHOD(getLexicalParentId) FORWARD_SYMBOL_METHOD(getLibraryName) FORWARD_SYMBOL_METHOD(getName) - FORWARD_SYMBOL_METHOD(getSourceFileName) - FORWARD_SYMBOL_METHOD(getSymIndexId) + + std::string getSourceFileName() const; }; } +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLCOMPILAND_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h index 7f29d6bde990..bb4a78f68e2f 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolCompilandDetails : public PDBSymbol { public: @@ -47,9 +48,10 @@ public: FORWARD_SYMBOL_METHOD(getLanguage) FORWARD_SYMBOL_METHOD(getLexicalParentId) FORWARD_SYMBOL_METHOD(getPlatform) - FORWARD_SYMBOL_METHOD(getSymIndexId) + FORWARD_SYMBOL_METHOD(getSourceFileName) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBFUNCTION_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h index 7e2ea9018edb..a71a0ba2df58 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h @@ -16,7 +16,7 @@ namespace llvm { class raw_ostream; - +namespace pdb { class PDBSymbolCompilandEnv : public PDBSymbol { public: PDBSymbolCompilandEnv(const IPDBSession &PDBSession, @@ -28,10 +28,10 @@ public: FORWARD_SYMBOL_METHOD(getLexicalParentId) FORWARD_SYMBOL_METHOD(getName) - FORWARD_SYMBOL_METHOD(getSymIndexId) std::string getValue() const; }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLCOMPILANDENV_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCustom.h b/include/llvm/DebugInfo/PDB/PDBSymbolCustom.h index 86bfd5707a31..54f089404262 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCustom.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCustom.h @@ -18,6 +18,7 @@ namespace llvm { class raw_ostream; +namespace pdb { /// PDBSymbolCustom represents symbols that are compiler-specific and do not /// fit anywhere else in the lexical hierarchy. /// https://msdn.microsoft.com/en-us/library/d88sf09h.aspx @@ -31,9 +32,9 @@ public: void dump(PDBSymDumper &Dumper) const override; void getDataBytes(llvm::SmallVector<uint8_t, 32> &bytes); - FORWARD_SYMBOL_METHOD(getSymIndexId) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLCUSTOM_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolData.h b/include/llvm/DebugInfo/PDB/PDBSymbolData.h index 79cbbf0e1683..36f32ab51c11 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolData.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolData.h @@ -17,6 +17,8 @@ namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolData : public PDBSymbol { public: PDBSymbolData(const IPDBSession &PDBSession, @@ -47,7 +49,6 @@ public: FORWARD_SYMBOL_METHOD(getRegisterId) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) FORWARD_SYMBOL_METHOD(getSlot) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getToken) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(isUnalignedType) @@ -57,5 +58,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLDATA_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolExe.h b/include/llvm/DebugInfo/PDB/PDBSymbolExe.h index 7c5f302ad634..5b3f50d153eb 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolExe.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolExe.h @@ -12,12 +12,13 @@ #include "PDBSymbol.h" #include "PDBTypes.h" -#include <string> namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolExe : public PDBSymbol { public: PDBSymbolExe(const IPDBSession &PDBSession, @@ -35,12 +36,12 @@ public: FORWARD_SYMBOL_METHOD(getName) FORWARD_SYMBOL_METHOD(getSignature) FORWARD_SYMBOL_METHOD(getSymbolsFileName) - FORWARD_SYMBOL_METHOD(getSymIndexId) private: void dumpChildren(raw_ostream &OS, StringRef Label, PDB_SymType ChildType, int Indent) const; }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLEXE_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h b/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h index 9db41d53532a..7170bcbe846c 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h @@ -17,6 +17,8 @@ namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolFunc : public PDBSymbol { public: PDBSymbolFunc(const IPDBSession &PDBSession, @@ -64,7 +66,6 @@ public: FORWARD_SYMBOL_METHOD(hasOptimizedCodeDebugInfo) FORWARD_SYMBOL_METHOD(isPureVirtual) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getToken) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(isUnalignedType) @@ -76,5 +77,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLFUNC_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h index 34d551cda74c..464389503bef 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h @@ -17,6 +17,8 @@ namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolFuncDebugEnd : public PDBSymbol { public: PDBSymbolFuncDebugEnd(const IPDBSession &PDBSession, @@ -40,10 +42,10 @@ public: FORWARD_SYMBOL_METHOD(getOffset) FORWARD_SYMBOL_METHOD(hasOptimizedCodeDebugInfo) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getVirtualAddress) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLFUNCDEBUGEND_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h index 7671be480dac..c2e3dd39be6c 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolFuncDebugStart : public PDBSymbol { public: @@ -40,10 +41,10 @@ public: FORWARD_SYMBOL_METHOD(getOffset) FORWARD_SYMBOL_METHOD(hasOptimizedCodeDebugInfo) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getVirtualAddress) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLFUNCDEBUGSTART_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h b/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h index 9d9903a11b0c..3aeae10b47bc 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolLabel : public PDBSymbol { public: @@ -40,10 +41,10 @@ public: FORWARD_SYMBOL_METHOD(getOffset) FORWARD_SYMBOL_METHOD(hasOptimizedCodeDebugInfo) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getVirtualAddress) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLLABEL_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h b/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h index 70dfcb5ddf4c..be0734445973 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolPublicSymbol : public PDBSymbol { public: @@ -36,12 +37,12 @@ public: FORWARD_SYMBOL_METHOD(isManagedCode) FORWARD_SYMBOL_METHOD(isMSILCode) FORWARD_SYMBOL_METHOD(getName) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) FORWARD_SYMBOL_METHOD(getVirtualAddress) FORWARD_SYMBOL_METHOD(getUndecoratedName) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLPUBLICSYMBOL_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h b/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h index bd5a9b2aa8b3..63f7a09fc881 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h @@ -12,11 +12,11 @@ #include "PDBSymbol.h" #include "PDBTypes.h" -#include <string> namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolThunk : public PDBSymbol { public: @@ -39,7 +39,6 @@ public: FORWARD_SYMBOL_METHOD(getName) FORWARD_SYMBOL_METHOD(isPureVirtual) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTargetOffset) FORWARD_SYMBOL_METHOD(getTargetRelativeVirtualAddress) FORWARD_SYMBOL_METHOD(getTargetVirtualAddress) @@ -53,5 +52,6 @@ public: FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTHUNK_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h index 513a9ec05ff8..57db03661fb7 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeArray : public PDBSymbol { public: @@ -34,12 +35,12 @@ public: FORWARD_SYMBOL_METHOD(getLength) FORWARD_SYMBOL_METHOD(getLexicalParentId) FORWARD_SYMBOL_METHOD(getRank) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEARRAY_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h index 2a9a8a0788a8..aaa3ab7988d7 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeBaseClass : public PDBSymbol { public: @@ -42,7 +43,6 @@ public: FORWARD_SYMBOL_METHOD(hasOverloadedOperator) FORWARD_SYMBOL_METHOD(isPacked) FORWARD_SYMBOL_METHOD(isScoped) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(getUdtKind) FORWARD_SYMBOL_METHOD(isUnalignedType) @@ -56,5 +56,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEBASECLASS_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h index 69a2028a1b1d..c8f59f1f140a 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeBuiltin : public PDBSymbol { public: @@ -30,11 +31,11 @@ public: FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(getLength) FORWARD_SYMBOL_METHOD(getLexicalParentId) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEBUILTIN_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h index c41c48933e0d..199b3f8b304e 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeCustom : public PDBSymbol { public: @@ -28,9 +29,9 @@ public: FORWARD_SYMBOL_METHOD(getOemId) FORWARD_SYMBOL_METHOD(getOemSymbolId) - FORWARD_SYMBOL_METHOD(getSymIndexId) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPECUSTOM_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h index 3f22ed8d731e..e635eb5bbf6f 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeDimension : public PDBSymbol { public: @@ -28,9 +29,9 @@ public: FORWARD_SYMBOL_METHOD(getLowerBoundId) FORWARD_SYMBOL_METHOD(getUpperBoundId) - FORWARD_SYMBOL_METHOD(getSymIndexId) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEDIMENSION_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h index 3188c711915c..ade2887bac14 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeEnum : public PDBSymbol { public: @@ -44,12 +45,12 @@ public: FORWARD_SYMBOL_METHOD(hasOverloadedOperator) FORWARD_SYMBOL_METHOD(isPacked) FORWARD_SYMBOL_METHOD(isScoped) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEENUM_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h index 4d393d7b6c5c..196d149ed2a2 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeFriend : public PDBSymbol { public: @@ -28,10 +29,10 @@ public: FORWARD_SYMBOL_METHOD(getClassParentId) FORWARD_SYMBOL_METHOD(getName) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEFRIEND_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h index 14f79d99b6f8..5561341d7e77 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeFunctionArg : public PDBSymbol { public: @@ -28,10 +29,10 @@ public: FORWARD_SYMBOL_METHOD(getClassParentId) FORWARD_SYMBOL_METHOD(getLexicalParentId) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEFUNCTIONARG_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h index 4bb4265a22f6..516011ff8b3d 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeFunctionSig : public PDBSymbol { public: @@ -38,7 +39,6 @@ public: FORWARD_SYMBOL_METHOD(getCount) FORWARD_SYMBOL_METHOD(getLexicalParentId) // FORWARD_SYMBOL_METHOD(getObjectPointerType) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getThisAdjust) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(isUnalignedType) @@ -46,5 +46,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEFUNCTIONSIG_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h index cbfcec82a637..31cf5363dde1 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeManaged : public PDBSymbol { public: @@ -27,9 +28,9 @@ public: void dump(PDBSymDumper &Dumper) const override; FORWARD_SYMBOL_METHOD(getName) - FORWARD_SYMBOL_METHOD(getSymIndexId) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEMANAGED_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h index 33578bad0245..7a57272adb79 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypePointer : public PDBSymbol { public: @@ -32,12 +33,12 @@ public: FORWARD_SYMBOL_METHOD(getLength) FORWARD_SYMBOL_METHOD(getLexicalParentId) FORWARD_SYMBOL_METHOD(isReference) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEPOINTER_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h index 5ad83bb1ec26..5ed4f8d21d90 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeTypedef : public PDBSymbol { public: @@ -41,7 +42,6 @@ public: FORWARD_SYMBOL_METHOD(isPacked) FORWARD_SYMBOL_METHOD(isReference) FORWARD_SYMBOL_METHOD(isScoped) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(getUdtKind) FORWARD_SYMBOL_METHOD(isUnalignedType) @@ -50,5 +50,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPETYPEDEF_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h index 99cc307a83e3..1874dfef34f7 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h @@ -17,6 +17,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeUDT : public PDBSymbol { public: PDBSymbolTypeUDT(const IPDBSession &PDBSession, @@ -40,13 +41,12 @@ public: FORWARD_SYMBOL_METHOD(hasOverloadedOperator) FORWARD_SYMBOL_METHOD(isPacked) FORWARD_SYMBOL_METHOD(isScoped) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getUdtKind) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(getVirtualTableShapeId) FORWARD_SYMBOL_METHOD(isVolatileType) }; - +} } // namespace llvm #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEUDT_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h index 6efc549f0cb7..baf7ab79d60e 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeVTable : public PDBSymbol { public: @@ -29,12 +30,12 @@ public: FORWARD_SYMBOL_METHOD(getClassParentId) FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(getLexicalParentId) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEVTABLE_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h index f407595a4cc8..431fc1ac8625 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeVTableShape : public PDBSymbol { public: @@ -29,11 +30,11 @@ public: FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(getCount) FORWARD_SYMBOL_METHOD(getLexicalParentId) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEVTABLESHAPE_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolUnknown.h b/include/llvm/DebugInfo/PDB/PDBSymbolUnknown.h index 94bd2c14079f..de43e47badbd 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolUnknown.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolUnknown.h @@ -15,6 +15,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolUnknown : public PDBSymbol { public: @@ -30,5 +31,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLUNKNOWN_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h b/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h index 7072f342bef3..a273fe159c12 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolUsingNamespace : public PDBSymbol { public: @@ -28,9 +29,9 @@ public: FORWARD_SYMBOL_METHOD(getLexicalParentId) FORWARD_SYMBOL_METHOD(getName) - FORWARD_SYMBOL_METHOD(getSymIndexId) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLUSINGNAMESPACE_H diff --git a/include/llvm/DebugInfo/PDB/PDBTypes.h b/include/llvm/DebugInfo/PDB/PDBTypes.h index a932a56bb953..a9325a434366 100644 --- a/include/llvm/DebugInfo/PDB/PDBTypes.h +++ b/include/llvm/DebugInfo/PDB/PDBTypes.h @@ -11,11 +11,13 @@ #define LLVM_DEBUGINFO_PDB_PDBTYPES_H #include "llvm/Config/llvm-config.h" -#include "llvm/Support/Endian.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" #include <functional> -#include <stdint.h> +#include <cstdint> +#include <cstring> namespace llvm { +namespace pdb { class PDBSymDumper; class PDBSymbol; @@ -68,14 +70,14 @@ class PDBSymbolUnknown; /// of PDB_ReaderType::DIA is supported. enum class PDB_ReaderType { DIA = 0, + Raw = 1, }; /// Defines a 128-bit unique identifier. This maps to a GUID on Windows, but /// is abstracted here for the purposes of non-Windows platforms that don't have /// the GUID structure defined. struct PDB_UniqueId { - uint64_t HighPart; - uint64_t LowPart; + char Guid[16]; }; /// An enumeration indicating the type of data contained in this table. @@ -108,67 +110,7 @@ enum class PDB_Checksum { None = 0, MD5 = 1, SHA1 = 2 }; /// 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 PDB_Cpu { - 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, -}; +typedef codeview::CPUType PDB_Cpu; enum class PDB_Machine { Invalid = 0xffff, @@ -200,56 +142,11 @@ enum class PDB_Machine { /// 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 PDB_CallingConv { - NearCdecl = 0x00, - FarCdecl = 0x01, - NearPascal = 0x02, - FarPascal = 0x03, - NearFastcall = 0x04, - FarFastcall = 0x05, - Skipped = 0x06, - NearStdcall = 0x07, - FarStdcall = 0x08, - NearSyscall = 0x09, - FarSyscall = 0x0a, - Thiscall = 0x0b, - MipsCall = 0x0c, - Generic = 0x0d, - Alphacall = 0x0e, - Ppccall = 0x0f, - SuperHCall = 0x10, - Armcall = 0x11, - AM33call = 0x12, - Tricall = 0x13, - Sh5call = 0x14, - M32R = 0x15, - Clrcall = 0x16, - Inline = 0x17, - NearVectorcall = 0x18, - Reserved = 0x19, -}; +typedef codeview::CallingConvention PDB_CallingConv; /// These values correspond to the CV_CFL_LANG enumeration, and are documented /// here: https://msdn.microsoft.com/en-us/library/bw3aekw6.aspx -enum class PDB_Lang { - 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 -}; +typedef codeview::SourceLanguage PDB_Lang; /// These values correspond to the DataKind enumeration, and are documented /// here: https://msdn.microsoft.com/en-us/library/b2x2t313.aspx @@ -320,18 +217,6 @@ enum class PDB_LocType { Max }; -/// These values correspond to the THUNK_ORDINAL enumeration, and are documented -/// here: https://msdn.microsoft.com/en-us/library/dh0k8hft.aspx -enum class PDB_ThunkOrdinal { - Standard, - ThisAdjustor, - Vcall, - Pcode, - UnknownLoad, - TrampIncremental, - BranchIsland -}; - /// These values correspond to the UdtKind enumeration, and are documented /// here: https://msdn.microsoft.com/en-us/library/wcstk66t.aspx enum class PDB_UdtType { Struct, Class, Union, Interface }; @@ -367,72 +252,8 @@ enum class PDB_BuiltinType { HResult = 31 }; -enum class PDB_RegisterId { - 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, -}; - enum class PDB_MemberAccess { Private = 1, Protected = 2, Public = 3 }; -enum class PDB_ErrorCode { - Success, - NoPdbImpl, - InvalidPath, - InvalidFileFormat, - InvalidParameter, - AlreadyLoaded, - UnknownError, - NoMemory, - DebugInfoMismatch -}; - struct VersionInfo { uint32_t Major; uint32_t Minor; @@ -454,11 +275,19 @@ enum PDB_VariantType { UInt32, UInt64, Bool, + String }; struct Variant { - Variant() - : Type(PDB_VariantType::Empty) { + Variant() : Type(PDB_VariantType::Empty) {} + + Variant(const Variant &Other) : Type(PDB_VariantType::Empty) { + *this = Other; + } + + ~Variant() { + if (Type == PDB_VariantType::String) + delete[] Value.String; } PDB_VariantType Type; @@ -474,10 +303,13 @@ struct Variant { uint16_t UInt16; uint32_t UInt32; uint64_t UInt64; - }; + char *String; + } Value; + #define VARIANT_EQUAL_CASE(Enum) \ case PDB_VariantType::Enum: \ - return Enum == Other.Enum; + return Value.Enum == Other.Value.Enum; + bool operator==(const Variant &Other) const { if (Type != Other.Type) return false; @@ -493,55 +325,43 @@ struct Variant { VARIANT_EQUAL_CASE(UInt16) VARIANT_EQUAL_CASE(UInt32) VARIANT_EQUAL_CASE(UInt64) + VARIANT_EQUAL_CASE(String) default: return true; } } + #undef VARIANT_EQUAL_CASE + bool operator!=(const Variant &Other) const { return !(*this == Other); } + Variant &operator=(const Variant &Other) { + if (this == &Other) + return *this; + if (Type == PDB_VariantType::String) + delete[] Value.String; + Type = Other.Type; + Value = Other.Value; + if (Other.Type == PDB_VariantType::String && + Other.Value.String != nullptr) { + Value.String = new char[strlen(Other.Value.String) + 1]; + ::strcpy(Value.String, Other.Value.String); + } + return *this; + } }; -namespace PDB { -static const char Magic[] = {'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', - 't', ' ', 'C', '/', 'C', '+', '+', ' ', - 'M', 'S', 'F', ' ', '7', '.', '0', '0', - '\r', '\n', '\x1a', 'D', 'S', '\0', '\0', '\0'}; - -// The superblock is overlaid at the beginning of the file (offset 0). -// It starts with a magic header and is followed by information which describes -// the layout of the file system. -struct SuperBlock { - char MagicBytes[sizeof(Magic)]; - // The file system is split into a variable number of fixed size elements. - // These elements are referred to as blocks. The size of a block may vary - // from system to system. - support::ulittle32_t BlockSize; - // This field's purpose is not yet known. - support::ulittle32_t Unknown0; - // This contains the number of blocks resident in the file system. In - // practice, NumBlocks * BlockSize is equivalent to the size of the PDB file. - support::ulittle32_t NumBlocks; - // This contains the number of bytes which make up the directory. - support::ulittle32_t NumDirectoryBytes; - // This field's purpose is not yet known. - support::ulittle32_t Unknown1; - // This contains the block # of the block map. - support::ulittle32_t BlockMapAddr; -}; +} // end namespace llvm } -} // namespace llvm - namespace std { -template <> struct hash<llvm::PDB_SymType> { - typedef llvm::PDB_SymType argument_type; +template <> struct hash<llvm::pdb::PDB_SymType> { + typedef llvm::pdb::PDB_SymType argument_type; typedef std::size_t result_type; result_type operator()(const argument_type &Arg) const { return std::hash<int>()(static_cast<int>(Arg)); } }; -} - +} // end namespace std -#endif +#endif // LLVM_DEBUGINFO_PDB_PDBTYPES_H diff --git a/include/llvm/DebugInfo/PDB/Raw/DbiStream.h b/include/llvm/DebugInfo/PDB/Raw/DbiStream.h new file mode 100644 index 000000000000..6ab3c8067558 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/DbiStream.h @@ -0,0 +1,149 @@ +//===- DbiStream.h - PDB Dbi Stream (Stream 3) Access -----------*- 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_RAW_PDBDBISTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H + +#include "llvm/DebugInfo/CodeView/ModuleSubstream.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/ModInfo.h" +#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace object { +struct FpoData; +struct coff_section; +} + +namespace pdb { +class DbiStreamBuilder; +class PDBFile; +class ISectionContribVisitor; + +class DbiStream { + friend class DbiStreamBuilder; + + struct HeaderInfo { + support::little32_t VersionSignature; + support::ulittle32_t VersionHeader; + support::ulittle32_t Age; // Should match InfoStream. + support::ulittle16_t GlobalSymbolStreamIndex; // Global symbol stream # + support::ulittle16_t BuildNumber; // See DbiBuildNo structure. + support::ulittle16_t PublicSymbolStreamIndex; // Public symbols stream # + support::ulittle16_t PdbDllVersion; // version of mspdbNNN.dll + support::ulittle16_t SymRecordStreamIndex; // Symbol records stream # + support::ulittle16_t PdbDllRbld; // rbld number of mspdbNNN.dll + support::little32_t ModiSubstreamSize; // Size of module info stream + support::little32_t SecContrSubstreamSize; // Size of sec. contrib stream + support::little32_t SectionMapSize; // Size of sec. map substream + support::little32_t FileInfoSize; // Size of file info substream + support::little32_t TypeServerSize; // Size of type server map + support::ulittle32_t MFCTypeServerIndex; // Index of MFC Type Server + support::little32_t OptionalDbgHdrSize; // Size of DbgHeader info + support::little32_t ECSubstreamSize; // Size of EC stream (what is EC?) + support::ulittle16_t Flags; // See DbiFlags enum. + support::ulittle16_t MachineType; // See PDB_MachineType enum. + + support::ulittle32_t Reserved; // Pad to 64 bytes + }; + +public: + DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream); + ~DbiStream(); + Error reload(); + + PdbRaw_DbiVer getDbiVersion() const; + uint32_t getAge() const; + uint16_t getPublicSymbolStreamIndex() const; + uint16_t getGlobalSymbolStreamIndex() const; + + uint16_t getFlags() const; + bool isIncrementallyLinked() const; + bool hasCTypes() const; + bool isStripped() const; + + uint16_t getBuildNumber() const; + uint16_t getBuildMajorVersion() const; + uint16_t getBuildMinorVersion() const; + + uint16_t getPdbDllRbld() const; + uint32_t getPdbDllVersion() const; + + uint32_t getSymRecordStreamIndex() const; + + PDB_Machine getMachineType() const; + + enum { InvalidStreamIndex = 0xffff }; + + /// If the given stream type is present, returns its stream index. If it is + /// not present, returns InvalidStreamIndex. + uint32_t getDebugStreamIndex(DbgHeaderType Type) const; + + ArrayRef<ModuleInfoEx> modules() const; + + Expected<StringRef> getFileNameForIndex(uint32_t Index) const; + + codeview::FixedStreamArray<object::coff_section> getSectionHeaders(); + + codeview::FixedStreamArray<object::FpoData> getFpoRecords(); + + codeview::FixedStreamArray<SecMapEntry> getSectionMap() const; + void visitSectionContributions(ISectionContribVisitor &Visitor) const; + + Error commit(); + +private: + Error initializeSectionContributionData(); + Error initializeSectionHeadersData(); + Error initializeSectionMapData(); + Error initializeFileInfo(); + Error initializeFpoRecords(); + + PDBFile &Pdb; + std::unique_ptr<MappedBlockStream> Stream; + + std::vector<ModuleInfoEx> ModuleInfos; + NameHashTable ECNames; + + codeview::StreamRef ModInfoSubstream; + codeview::StreamRef SecContrSubstream; + codeview::StreamRef SecMapSubstream; + codeview::StreamRef FileInfoSubstream; + codeview::StreamRef TypeServerMapSubstream; + codeview::StreamRef ECSubstream; + + codeview::StreamRef NamesBuffer; + + codeview::FixedStreamArray<support::ulittle16_t> DbgStreams; + + PdbRaw_DbiSecContribVer SectionContribVersion; + codeview::FixedStreamArray<SectionContrib> SectionContribs; + codeview::FixedStreamArray<SectionContrib2> SectionContribs2; + codeview::FixedStreamArray<SecMapEntry> SectionMap; + codeview::FixedStreamArray<support::little32_t> FileNameOffsets; + + std::unique_ptr<MappedBlockStream> SectionHeaderStream; + codeview::FixedStreamArray<object::coff_section> SectionHeaders; + + std::unique_ptr<MappedBlockStream> FpoStream; + codeview::FixedStreamArray<object::FpoData> FpoRecords; + + const HeaderInfo *Header; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h b/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h new file mode 100644 index 000000000000..2c7350f3c3e7 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h @@ -0,0 +1,56 @@ +//===- DbiStreamBuilder.h - PDB Dbi Stream Creation -------------*- 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_RAW_PDBDBISTREAMBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAMBUILDER_H + +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Error.h" + +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" + +namespace llvm { +namespace pdb { +class DbiStream; +class PDBFile; + +class DbiStreamBuilder { +public: + DbiStreamBuilder(); + + DbiStreamBuilder(const DbiStreamBuilder &) = delete; + DbiStreamBuilder &operator=(const DbiStreamBuilder &) = delete; + + void setVersionHeader(PdbRaw_DbiVer V); + void setAge(uint32_t A); + void setBuildNumber(uint16_t B); + void setPdbDllVersion(uint16_t V); + void setPdbDllRbld(uint16_t R); + void setFlags(uint16_t F); + void setMachineType(PDB_Machine M); + + uint32_t calculateSerializedLength() const; + + Expected<std::unique_ptr<DbiStream>> build(PDBFile &File); + +private: + Optional<PdbRaw_DbiVer> VerHeader; + uint32_t Age; + uint16_t BuildNumber; + uint16_t PdbDllVersion; + uint16_t PdbDllRbld; + uint16_t Flags; + PDB_Machine MachineType; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h b/include/llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h new file mode 100644 index 000000000000..0f354315122c --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h @@ -0,0 +1,37 @@ +//===- DirectoryStreamData.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_PDB_RAW_DIRECTORYSTREAMDATA_H +#define LLVM_DEBUGINFO_PDB_RAW_DIRECTORYSTREAMDATA_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace pdb { +class IPDBFile; + +class DirectoryStreamData : public IPDBStreamData { +public: + DirectoryStreamData(const PDBFile &File) : File(File) {} + + virtual uint32_t getLength() { return File.getNumDirectoryBytes(); } + virtual llvm::ArrayRef<llvm::support::ulittle32_t> getStreamBlocks() { + return File.getDirectoryBlockArray(); + } + +private: + const PDBFile &File; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/EnumTables.h b/include/llvm/DebugInfo/PDB/Raw/EnumTables.h new file mode 100644 index 000000000000..c018445630fe --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/EnumTables.h @@ -0,0 +1,22 @@ +//===- 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_PDB_RAW_ENUMTABLES_H +#define LLVM_DEBUGINFO_PDB_RAW_ENUMTABLES_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/ScopedPrinter.h" + +namespace llvm { +namespace pdb { +ArrayRef<EnumEntry<uint16_t>> getOMFSegMapDescFlagNames(); +} +} + +#endif // LLVM_DEBUGINFO_PDB_RAW_ENUMTABLES_H diff --git a/include/llvm/DebugInfo/PDB/Raw/Hash.h b/include/llvm/DebugInfo/PDB/Raw/Hash.h new file mode 100644 index 000000000000..0340554d7b0b --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/Hash.h @@ -0,0 +1,25 @@ +//===- Hash.h - PDB hash functions ------------------------------*- 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_RAW_HASH_H +#define LLVM_DEBUGINFO_PDB_RAW_HASH_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include <stdint.h> + +namespace llvm { +namespace pdb { +uint32_t hashStringV1(StringRef Str); +uint32_t hashStringV2(StringRef Str); +uint32_t hashBufferV8(ArrayRef<uint8_t> Data); +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/IPDBFile.h b/include/llvm/DebugInfo/PDB/Raw/IPDBFile.h new file mode 100644 index 000000000000..fccea2ac2470 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/IPDBFile.h @@ -0,0 +1,44 @@ +//===- IPDBFile.h - Abstract base class for a PDB file ----------*- 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_RAW_IPDBFILE_H +#define LLVM_DEBUGINFO_PDB_RAW_IPDBFILE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +#include <stdint.h> + +namespace llvm { +namespace pdb { + +class IPDBFile { +public: + virtual ~IPDBFile() {} + + virtual uint32_t getBlockSize() const = 0; + virtual uint32_t getBlockCount() const = 0; + + virtual uint32_t getNumStreams() const = 0; + virtual uint32_t getStreamByteSize(uint32_t StreamIndex) const = 0; + virtual ArrayRef<support::ulittle32_t> + getStreamBlockList(uint32_t StreamIndex) const = 0; + + virtual Expected<ArrayRef<uint8_t>> getBlockData(uint32_t BlockIndex, + uint32_t NumBytes) const = 0; + virtual Error setBlockData(uint32_t BlockIndex, uint32_t Offset, + ArrayRef<uint8_t> Data) const = 0; +}; +} +} + +#endif // LLVM_DEBUGINFO_PDB_RAW_IPDBFILE_H diff --git a/include/llvm/DebugInfo/PDB/Raw/IPDBStreamData.h b/include/llvm/DebugInfo/PDB/Raw/IPDBStreamData.h new file mode 100644 index 000000000000..ab3c9f770755 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/IPDBStreamData.h @@ -0,0 +1,38 @@ +//===- IPDBStreamData.h - Base interface for PDB Stream 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_PDB_RAW_IPDBSTREAMDATA_H +#define LLVM_DEBUGINFO_PDB_RAW_IPDBSTREAMDATA_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace pdb { +/// IPDBStream abstracts the notion of PDB stream data. Although we already +/// have another stream abstraction (namely in the form of StreamInterface +/// and MappedBlockStream), they assume that the stream data is referenced +/// the same way. Namely, by looking in the directory to get the list of +/// stream blocks, and by looking in the array of stream lengths to get the +/// length. This breaks down for the directory itself, however, since its +/// length and list of blocks are stored elsewhere. By abstracting the +/// notion of stream data further, we can use a MappedBlockStream to read +/// from the directory itself, or from an indexed stream which references +/// the directory. +class IPDBStreamData { +public: + virtual ~IPDBStreamData() {} + + virtual uint32_t getLength() = 0; + virtual ArrayRef<support::ulittle32_t> getStreamBlocks() = 0; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h b/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h new file mode 100644 index 000000000000..355a25a38ef8 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h @@ -0,0 +1,28 @@ +//===- ISectionContribVisitor.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_PDB_RAW_ISECTIONCONTRIBVISITOR_H +#define LLVM_DEBUGINFO_PDB_RAW_ISECTIONCONTRIBVISITOR_H + +namespace llvm { +namespace pdb { +struct SectionContrib; +struct SectionContrib2; + +class ISectionContribVisitor { +public: + virtual ~ISectionContribVisitor() {} + + virtual void visit(const SectionContrib &C) = 0; + virtual void visit(const SectionContrib2 &C) = 0; +}; +} // namespace pdb +} // namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_ISECTIONCONTRIBVISITOR_H diff --git a/include/llvm/DebugInfo/PDB/Raw/IndexedStreamData.h b/include/llvm/DebugInfo/PDB/Raw/IndexedStreamData.h new file mode 100644 index 000000000000..30563bc5b898 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/IndexedStreamData.h @@ -0,0 +1,34 @@ +//===- IndexedStreamData.h - Standard PDB Stream 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_PDB_RAW_INDEXEDSTREAMDATA_H +#define LLVM_DEBUGINFO_PDB_RAW_INDEXEDSTREAMDATA_H + +#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" + +namespace llvm { +namespace pdb { +class IPDBFile; + +class IndexedStreamData : public IPDBStreamData { +public: + IndexedStreamData(uint32_t StreamIdx, const IPDBFile &File); + virtual ~IndexedStreamData() {} + + uint32_t getLength() override; + ArrayRef<support::ulittle32_t> getStreamBlocks() override; + +private: + uint32_t StreamIdx; + const IPDBFile &File; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/InfoStream.h b/include/llvm/DebugInfo/PDB/Raw/InfoStream.h new file mode 100644 index 000000000000..1980bec7153e --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/InfoStream.h @@ -0,0 +1,77 @@ +//===- InfoStream.h - PDB Info Stream (Stream 1) Access ---------*- 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_RAW_PDBINFOSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAM_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/NameMap.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" + +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class InfoStreamBuilder; +class PDBFile; + +class InfoStream { + friend class InfoStreamBuilder; + + struct HeaderInfo { + support::ulittle32_t Version; + support::ulittle32_t Signature; + support::ulittle32_t Age; + PDB_UniqueId Guid; + }; + +public: + InfoStream(std::unique_ptr<MappedBlockStream> Stream); + + Error reload(); + Error commit(); + + PdbRaw_ImplVer getVersion() const; + uint32_t getSignature() const; + uint32_t getAge() const; + PDB_UniqueId getGuid() const; + + uint32_t getNamedStreamIndex(llvm::StringRef Name) const; + iterator_range<StringMapConstIterator<uint32_t>> named_streams() const; + +private: + std::unique_ptr<MappedBlockStream> Stream; + + // PDB file format version. We only support VC70. See the enumeration + // `PdbRaw_ImplVer` for the other possible values. + uint32_t Version; + + // A 32-bit signature unique across all PDBs. This is generated with + // a call to time() when the PDB is written, but obviously this is not + // universally unique. + uint32_t Signature; + + // The number of times the PDB has been written. Might also be used to + // ensure that the PDB matches the executable. + uint32_t Age; + + // Due to the aforementioned limitations with `Signature`, this is a new + // signature present on VC70 and higher PDBs which is guaranteed to be + // universally unique. + PDB_UniqueId Guid; + + NameMap NamedStreams; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h b/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h new file mode 100644 index 000000000000..e9869bb27863 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h @@ -0,0 +1,53 @@ +//===- InfoStreamBuilder.h - PDB Info Stream Creation -----------*- 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_RAW_PDBINFOSTREAMBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAMBUILDER_H + +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Error.h" + +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/NameMapBuilder.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class InfoStreamBuilder { +public: + InfoStreamBuilder(); + InfoStreamBuilder(const InfoStreamBuilder &) = delete; + InfoStreamBuilder &operator=(const InfoStreamBuilder &) = delete; + + void setVersion(PdbRaw_ImplVer V); + void setSignature(uint32_t S); + void setAge(uint32_t A); + void setGuid(PDB_UniqueId G); + + NameMapBuilder &getNamedStreamsBuilder(); + + uint32_t calculateSerializedLength() const; + + Expected<std::unique_ptr<InfoStream>> build(PDBFile &File); + +private: + Optional<PdbRaw_ImplVer> Ver; + Optional<uint32_t> Sig; + Optional<uint32_t> Age; + Optional<PDB_UniqueId> Guid; + + NameMapBuilder NamedStreams; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h b/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h new file mode 100644 index 000000000000..36424c0d16ab --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h @@ -0,0 +1,68 @@ +//===- MappedBlockStream.h - Reads stream data from a PDBFile ---*- 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_RAW_MAPPEDBLOCKSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_MAPPEDBLOCKSTREAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <cstdint> +#include <vector> + +namespace llvm { +namespace pdb { + +class IPDBFile; +class PDBFile; + +class MappedBlockStream : public codeview::StreamInterface { +public: + 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; + + uint32_t getNumBytesCopied() const; + + static Expected<std::unique_ptr<MappedBlockStream>> + createIndexedStream(uint32_t StreamIdx, const IPDBFile &File); + static Expected<std::unique_ptr<MappedBlockStream>> + createDirectoryStream(const PDBFile &File); + + llvm::BumpPtrAllocator &getAllocator() { return Pool; } + +protected: + MappedBlockStream(std::unique_ptr<IPDBStreamData> Data, const IPDBFile &File); + + Error readBytes(uint32_t Offset, MutableArrayRef<uint8_t> Buffer) const; + bool tryReadContiguously(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) const; + + const IPDBFile &Pdb; + std::unique_ptr<IPDBStreamData> Data; + + typedef MutableArrayRef<uint8_t> CacheEntry; + mutable llvm::BumpPtrAllocator Pool; + mutable DenseMap<uint32_t, std::vector<CacheEntry>> CacheMap; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_MAPPEDBLOCKSTREAM_H diff --git a/include/llvm/DebugInfo/PDB/Raw/ModInfo.h b/include/llvm/DebugInfo/PDB/Raw/ModInfo.h new file mode 100644 index 000000000000..b8da0bfabf38 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/ModInfo.h @@ -0,0 +1,79 @@ +//===- ModInfo.h - PDB module information -----------------------*- 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_RAW_MODINFO_H +#define LLVM_DEBUGINFO_PDB_RAW_MODINFO_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include <cstdint> +#include <vector> + +namespace llvm { +namespace pdb { + +class ModInfo { +private: + struct FileLayout; + +public: + ModInfo(); + ModInfo(const ModInfo &Info); + ~ModInfo(); + + static Error initialize(codeview::StreamRef Stream, ModInfo &Info); + + bool hasECInfo() const; + uint16_t getTypeServerIndex() const; + uint16_t getModuleStreamIndex() const; + uint32_t getSymbolDebugInfoByteSize() const; + uint32_t getLineInfoByteSize() const; + uint32_t getC13LineInfoByteSize() const; + uint32_t getNumberOfFiles() const; + uint32_t getSourceFileNameIndex() const; + uint32_t getPdbFilePathNameIndex() const; + + StringRef getModuleName() const; + StringRef getObjFileName() const; + + uint32_t getRecordLength() const; + +private: + StringRef ModuleName; + StringRef ObjFileName; + const FileLayout *Layout; +}; + +struct ModuleInfoEx { + ModuleInfoEx(const ModInfo &Info) : Info(Info) {} + ModuleInfoEx(const ModuleInfoEx &Ex) + : Info(Ex.Info), SourceFiles(Ex.SourceFiles) {} + + ModInfo Info; + std::vector<StringRef> SourceFiles; +}; + +} // end namespace pdb + +namespace codeview { +template <> struct VarStreamArrayExtractor<pdb::ModInfo> { + Error operator()(StreamRef Stream, uint32_t &Length, + pdb::ModInfo &Info) const { + if (auto EC = pdb::ModInfo::initialize(Stream, Info)) + return EC; + Length = Info.getRecordLength(); + return Error::success(); + } +}; +} + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_MODINFO_H diff --git a/include/llvm/DebugInfo/PDB/Raw/ModStream.h b/include/llvm/DebugInfo/PDB/Raw/ModStream.h new file mode 100644 index 000000000000..d22962cc1e28 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/ModStream.h @@ -0,0 +1,57 @@ +//===- ModStream.h - PDB Module Info Stream Access ------------------------===// +// +// 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_RAW_MODSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_MODSTREAM_H + +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/ModuleSubstream.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; +class ModInfo; + +class ModStream { +public: + ModStream(const ModInfo &Module, std::unique_ptr<MappedBlockStream> Stream); + ~ModStream(); + + Error reload(); + + iterator_range<codeview::CVSymbolArray::Iterator> + symbols(bool *HadError) const; + + iterator_range<codeview::ModuleSubstreamArray::Iterator> + lines(bool *HadError) const; + + Error commit(); + +private: + const ModInfo &Mod; + + std::unique_ptr<MappedBlockStream> Stream; + + codeview::CVSymbolArray SymbolsSubstream; + codeview::StreamRef LinesSubstream; + codeview::StreamRef C13LinesSubstream; + codeview::StreamRef GlobalRefsSubstream; + + codeview::ModuleSubstreamArray LineInfo; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/MsfBuilder.h b/include/llvm/DebugInfo/PDB/Raw/MsfBuilder.h new file mode 100644 index 000000000000..92d9bc042cce --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/MsfBuilder.h @@ -0,0 +1,141 @@ +//===- MSFBuilder.h - MSF Directory & Metadata Builder ----------*- 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_RAW_MSFBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_MSFBUILDER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" + +#include "llvm/DebugInfo/PDB/Raw/MsfCommon.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" + +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +#include <utility> +#include <vector> + +namespace llvm { +namespace pdb { +class MsfBuilder { +public: + /// \brief Create a new `MsfBuilder`. + /// + /// \param BlockSize The internal block size used by the PDB file. See + /// isValidBlockSize() for a list of valid block sizes. + /// + /// \param MinBlockCount Causes the builder to reserve up front space for + /// at least `MinBlockCount` blocks. This is useful when using `MsfBuilder` + /// to read an existing PDB that you want to write back out later. The + /// original PDB file's SuperBlock contains the exact number of blocks used + /// by the file, so is a good hint as to how many blocks the new PDB file + /// will contain. Furthermore, it is actually necessary in this case. To + /// preserve stability of the file's layout, it is helpful to try to keep + /// all streams mapped to their original block numbers. To ensure that this + /// is possible, space for all blocks must be allocated beforehand so that + /// streams can be assigned to them. + /// + /// \param CanGrow If true, any operation which results in an attempt to + /// locate a free block when all available blocks have been exhausted will + /// allocate a new block, thereby growing the size of the final PDB file. + /// When false, any such attempt will result in an error. This is especially + /// useful in testing scenarios when you know your test isn't going to do + /// anything to increase the size of the file, so having an Error returned if + /// it were to happen would catch a programming error + /// + /// \returns an llvm::Error representing whether the operation succeeded or + /// failed. Currently the only way this can fail is if an invalid block size + /// is specified, or `MinBlockCount` does not leave enough room for the + /// mandatory reserved blocks required by an MSF file. + static Expected<MsfBuilder> create(BumpPtrAllocator &Allocator, + uint32_t BlockSize, + uint32_t MinBlockCount = 0, + bool CanGrow = true); + + /// Request the block map to be at a specific block address. This is useful + /// when editing a PDB and you want the layout to be as stable as possible. + Error setBlockMapAddr(uint32_t Addr); + Error setDirectoryBlocksHint(ArrayRef<uint32_t> DirBlocks); + void setFreePageMap(uint32_t Fpm); + void setUnknown1(uint32_t Unk1); + + /// Add a stream to the MSF file with the given size, occupying the given + /// list of blocks. This is useful when reading a PDB file and you want a + /// particular stream to occupy the original set of blocks. If the given + /// blocks are already allocated, or if the number of blocks specified is + /// incorrect for the given stream size, this function will return an Error. + Error addStream(uint32_t Size, ArrayRef<uint32_t> Blocks); + + /// Add a stream to the MSF file with the given size, occupying any available + /// blocks that the builder decides to use. This is useful when building a + /// new PDB file from scratch and you don't care what blocks a stream occupies + /// but you just want it to work. + Error addStream(uint32_t Size); + + /// Update the size of an existing stream. This will allocate or deallocate + /// blocks as needed to match the requested size. This can fail if `CanGrow` + /// was set to false when initializing the `MsfBuilder`. + Error setStreamSize(uint32_t Idx, uint32_t Size); + + /// Get the total number of streams in the MSF layout. This should return 1 + /// for every call to `addStream`. + uint32_t getNumStreams() const; + + /// Get the size of a stream by index. + uint32_t getStreamSize(uint32_t StreamIdx) const; + + /// Get the list of blocks allocated to a particular stream. + ArrayRef<uint32_t> getStreamBlocks(uint32_t StreamIdx) const; + + /// Get the total number of blocks that will be allocated to actual data in + /// this MSF file. + uint32_t getNumUsedBlocks() const; + + /// Get the total number of blocks that exist in the MSF file but are not + /// allocated to any valid data. + uint32_t getNumFreeBlocks() const; + + /// Get the total number of blocks in the MSF file. In practice this is equal + /// to `getNumUsedBlocks() + getNumFreeBlocks()`. + uint32_t getTotalBlockCount() const; + + /// Check whether a particular block is allocated or free. + bool isBlockFree(uint32_t Idx) const; + + /// Finalize the layout and build the headers and structures that describe the + /// MSF layout and can be written directly to the MSF file. + Expected<msf::Layout> build(); + +private: + MsfBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow, + BumpPtrAllocator &Allocator); + + Error allocateBlocks(uint32_t NumBlocks, MutableArrayRef<uint32_t> Blocks); + uint32_t computeDirectoryByteSize() const; + + typedef std::vector<uint32_t> BlockList; + + BumpPtrAllocator &Allocator; + + bool IsGrowable; + uint32_t FreePageMap; + uint32_t Unknown1; + uint32_t BlockSize; + uint32_t MininumBlocks; + uint32_t BlockMapAddr; + BitVector FreeBlocks; + std::vector<uint32_t> DirectoryBlocks; + std::vector<std::pair<uint32_t, BlockList>> StreamData; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/MsfCommon.h b/include/llvm/DebugInfo/PDB/Raw/MsfCommon.h new file mode 100644 index 000000000000..2f6a6986eba9 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/MsfCommon.h @@ -0,0 +1,90 @@ +//===- MsfCommon.h - Common types and functions for MSF files ---*- 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_RAW_MSFCOMMON_H +#define LLVM_DEBUGINFO_PDB_RAW_MSFCOMMON_H + +#include "llvm/ADT/ArrayRef.h" + +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" + +#include <vector> + +namespace llvm { +namespace pdb { +namespace msf { +static const char Magic[] = {'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', + 't', ' ', 'C', '/', 'C', '+', '+', ' ', + 'M', 'S', 'F', ' ', '7', '.', '0', '0', + '\r', '\n', '\x1a', 'D', 'S', '\0', '\0', '\0'}; + +// The superblock is overlaid at the beginning of the file (offset 0). +// It starts with a magic header and is followed by information which +// describes the layout of the file system. +struct SuperBlock { + char MagicBytes[sizeof(Magic)]; + // The file system is split into a variable number of fixed size elements. + // These elements are referred to as blocks. The size of a block may vary + // from system to system. + support::ulittle32_t BlockSize; + // The index of the free block map. + support::ulittle32_t FreeBlockMapBlock; + // This contains the number of blocks resident in the file system. In + // practice, NumBlocks * BlockSize is equivalent to the size of the PDB + // file. + support::ulittle32_t NumBlocks; + // This contains the number of bytes which make up the directory. + support::ulittle32_t NumDirectoryBytes; + // This field's purpose is not yet known. + support::ulittle32_t Unknown1; + // This contains the block # of the block map. + support::ulittle32_t BlockMapAddr; +}; + +struct Layout { + SuperBlock *SB; + ArrayRef<support::ulittle32_t> DirectoryBlocks; + ArrayRef<support::ulittle32_t> StreamSizes; + std::vector<ArrayRef<support::ulittle32_t>> StreamMap; +}; + +inline bool isValidBlockSize(uint32_t Size) { + switch (Size) { + case 512: + case 1024: + case 2048: + case 4096: + return true; + } + return false; +} + +// Super Block, Fpm0, Fpm1, and Block Map +inline uint32_t getMinimumBlockCount() { return 4; } + +// Super Block, Fpm0, and Fpm1 are reserved. The Block Map, although required +// need not be at block 3. +inline uint32_t getFirstUnreservedBlock() { return 3; } + +inline uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) { + return alignTo(NumBytes, BlockSize) / BlockSize; +} + +inline uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize) { + return BlockNumber * BlockSize; +} + +Error validateSuperBlock(const SuperBlock &SB); +} +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h b/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h new file mode 100644 index 000000000000..c9e060a3a70f --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h @@ -0,0 +1,54 @@ +//===- NameHashTable.h - PDB Name Hash Table --------------------*- 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_RAW_NAMEHASHTABLE_H +#define LLVM_DEBUGINFO_PDB_RAW_NAMEHASHTABLE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <cstdint> +#include <vector> + +namespace llvm { +namespace codeview { +class StreamReader; +} +namespace pdb { + +class NameHashTable { +public: + NameHashTable(); + + Error load(codeview::StreamReader &Stream); + + uint32_t getNameCount() const { return NameCount; } + uint32_t getHashVersion() const { return HashVersion; } + uint32_t getSignature() const { return Signature; } + + StringRef getStringForID(uint32_t ID) const; + uint32_t getIDForString(StringRef Str) const; + + codeview::FixedStreamArray<support::ulittle32_t> name_ids() const; + +private: + codeview::StreamRef NamesBuffer; + codeview::FixedStreamArray<support::ulittle32_t> IDs; + uint32_t Signature; + uint32_t HashVersion; + uint32_t NameCount; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_NAMEHASHTABLE_H diff --git a/include/llvm/DebugInfo/PDB/Raw/NameMap.h b/include/llvm/DebugInfo/PDB/Raw/NameMap.h new file mode 100644 index 000000000000..8a9b0d187ace --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/NameMap.h @@ -0,0 +1,45 @@ +//===- NameMap.h - PDB Name Map ---------------------------------*- 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_RAW_PDBNAMEMAP_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAP_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include <cstdint> + +namespace llvm { +namespace codeview { +class StreamReader; +class StreamWriter; +} +namespace pdb { +class NameMapBuilder; +class NameMap { + friend NameMapBuilder; + +public: + NameMap(); + + Error load(codeview::StreamReader &Stream); + Error commit(codeview::StreamWriter &Writer); + + bool tryGetValue(StringRef Name, uint32_t &Value) const; + + iterator_range<StringMapConstIterator<uint32_t>> entries() const; + +private: + StringMap<uint32_t> Mapping; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAP_H diff --git a/include/llvm/DebugInfo/PDB/Raw/NameMapBuilder.h b/include/llvm/DebugInfo/PDB/Raw/NameMapBuilder.h new file mode 100644 index 000000000000..bf49bfd9bf2e --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/NameMapBuilder.h @@ -0,0 +1,41 @@ +//===- NameMapBuilder.h - PDB Name Map Builder ------------------*- 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_RAW_PDBNAMEMAPBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAPBUILDER_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Error.h" + +#include <cstdint> +#include <memory> + +namespace llvm { +namespace pdb { +class NameMap; + +class NameMapBuilder { +public: + NameMapBuilder(); + + void addMapping(StringRef Name, uint32_t Mapping); + + Expected<std::unique_ptr<NameMap>> build(); + + uint32_t calculateSerializedLength() const; + +private: + StringMap<uint32_t> Map; + uint32_t StringDataBytes = 0; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAPBUILDER_H diff --git a/include/llvm/DebugInfo/PDB/Raw/PDBFile.h b/include/llvm/DebugInfo/PDB/Raw/PDBFile.h new file mode 100644 index 000000000000..f4d7eb47d3b9 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/PDBFile.h @@ -0,0 +1,113 @@ +//===- PDBFile.h - Low level interface to a PDB file ------------*- 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_RAW_PDBFILE_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBFILE_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/MsfCommon.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" + +#include <memory> + +namespace llvm { + +namespace codeview { +class StreamInterface; +} + +namespace pdb { +class DbiStream; +class InfoStream; +class MappedBlockStream; +class NameHashTable; +class PDBFileBuilder; +class PublicsStream; +class SymbolStream; +class TpiStream; + +class PDBFile : public IPDBFile { + friend PDBFileBuilder; + +public: + explicit PDBFile(std::unique_ptr<codeview::StreamInterface> PdbFileBuffer); + ~PDBFile() override; + + uint32_t getFreeBlockMapBlock() const; + uint32_t getUnknown1() const; + + uint32_t getBlockSize() const override; + uint32_t getBlockCount() const override; + uint32_t getNumDirectoryBytes() const; + uint32_t getBlockMapIndex() const; + uint32_t getNumDirectoryBlocks() const; + uint64_t getBlockMapOffset() const; + + uint32_t getNumStreams() const override; + uint32_t getStreamByteSize(uint32_t StreamIndex) const override; + ArrayRef<support::ulittle32_t> + getStreamBlockList(uint32_t StreamIndex) const override; + uint32_t getFileSize() const; + + Expected<ArrayRef<uint8_t>> getBlockData(uint32_t BlockIndex, + uint32_t NumBytes) const override; + Error setBlockData(uint32_t BlockIndex, uint32_t Offset, + ArrayRef<uint8_t> Data) const override; + + ArrayRef<support::ulittle32_t> getStreamSizes() const { return StreamSizes; } + ArrayRef<ArrayRef<support::ulittle32_t>> getStreamMap() const { + return StreamMap; + } + + ArrayRef<support::ulittle32_t> getDirectoryBlockArray() const; + + Error parseFileHeaders(); + Error parseStreamData(); + + Expected<InfoStream &> getPDBInfoStream(); + Expected<DbiStream &> getPDBDbiStream(); + Expected<TpiStream &> getPDBTpiStream(); + Expected<TpiStream &> getPDBIpiStream(); + Expected<PublicsStream &> getPDBPublicsStream(); + Expected<SymbolStream &> getPDBSymbolStream(); + Expected<NameHashTable &> getStringTable(); + + Error commit(); + +private: + Error setSuperBlock(const msf::SuperBlock *Block); + + BumpPtrAllocator Allocator; + + std::unique_ptr<codeview::StreamInterface> Buffer; + const msf::SuperBlock *SB; + ArrayRef<support::ulittle32_t> StreamSizes; + ArrayRef<support::ulittle32_t> DirectoryBlocks; + std::vector<ArrayRef<support::ulittle32_t>> StreamMap; + + std::unique_ptr<InfoStream> Info; + std::unique_ptr<DbiStream> Dbi; + std::unique_ptr<TpiStream> Tpi; + std::unique_ptr<TpiStream> Ipi; + std::unique_ptr<PublicsStream> Publics; + std::unique_ptr<SymbolStream> Symbols; + std::unique_ptr<MappedBlockStream> DirectoryStream; + std::unique_ptr<MappedBlockStream> StringTableStream; + std::unique_ptr<NameHashTable> StringTable; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h b/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h new file mode 100644 index 000000000000..47c755b43269 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h @@ -0,0 +1,59 @@ +//===- PDBFileBuilder.h - PDB File Creation ---------------------*- 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_RAW_PDBFILEBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBFILEBUILDER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +#include "llvm/DebugInfo/PDB/Raw/MsfBuilder.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" + +#include <memory> +#include <vector> + +namespace llvm { +namespace codeview { +class StreamInterface; +} +namespace pdb { +class DbiStreamBuilder; +class InfoStreamBuilder; +class PDBFile; + +class PDBFileBuilder { +public: + explicit PDBFileBuilder( + std::unique_ptr<codeview::StreamInterface> FileBuffer); + PDBFileBuilder(const PDBFileBuilder &) = delete; + PDBFileBuilder &operator=(const PDBFileBuilder &) = delete; + + Error initialize(const msf::SuperBlock &Super); + + MsfBuilder &getMsfBuilder(); + InfoStreamBuilder &getInfoBuilder(); + DbiStreamBuilder &getDbiBuilder(); + + Expected<std::unique_ptr<PDBFile>> build(); + +private: + std::unique_ptr<InfoStreamBuilder> Info; + std::unique_ptr<DbiStreamBuilder> Dbi; + + std::unique_ptr<PDBFile> File; + std::unique_ptr<MsfBuilder> Msf; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h b/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h new file mode 100644 index 000000000000..f5bfb0ed60a9 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h @@ -0,0 +1,74 @@ +//===- PublicsStream.h - PDB Public Symbol 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_PDB_RAW_PUBLICSSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PUBLICSSTREAM_H + +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class DbiStream; +class PDBFile; + +class PublicsStream { + struct GSIHashHeader; + struct HeaderInfo; + +public: + PublicsStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream); + ~PublicsStream(); + Error reload(); + + uint32_t getSymHash() const; + uint32_t getAddrMap() const; + uint32_t getNumBuckets() const { return NumBuckets; } + iterator_range<codeview::CVSymbolArray::Iterator> + getSymbols(bool *HadError) const; + codeview::FixedStreamArray<support::ulittle32_t> getHashBuckets() const { + return HashBuckets; + } + codeview::FixedStreamArray<support::ulittle32_t> getAddressMap() const { + return AddressMap; + } + codeview::FixedStreamArray<support::ulittle32_t> getThunkMap() const { + return ThunkMap; + } + codeview::FixedStreamArray<SectionOffset> getSectionOffsets() const { + return SectionOffsets; + } + + Error commit(); + +private: + PDBFile &Pdb; + + std::unique_ptr<MappedBlockStream> Stream; + uint32_t NumBuckets = 0; + ArrayRef<uint8_t> Bitmap; + codeview::FixedStreamArray<PSHashRecord> HashRecords; + codeview::FixedStreamArray<support::ulittle32_t> HashBuckets; + codeview::FixedStreamArray<support::ulittle32_t> AddressMap; + codeview::FixedStreamArray<support::ulittle32_t> ThunkMap; + codeview::FixedStreamArray<SectionOffset> SectionOffsets; + + const HeaderInfo *Header; + const GSIHashHeader *HashHdr; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/RawConstants.h b/include/llvm/DebugInfo/PDB/Raw/RawConstants.h new file mode 100644 index 000000000000..8daaf47882d8 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/RawConstants.h @@ -0,0 +1,94 @@ +//===- RawConstants.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_PDB_RAW_PDBRAWCONSTANTS_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBRAWCONSTANTS_H + +#include "llvm/DebugInfo/CodeView/CodeView.h" + +#include <cstdint> + +namespace llvm { +namespace pdb { + +enum PdbRaw_ImplVer : uint32_t { + PdbImplVC2 = 19941610, + PdbImplVC4 = 19950623, + PdbImplVC41 = 19950814, + PdbImplVC50 = 19960307, + PdbImplVC98 = 19970604, + PdbImplVC70Dep = 19990604, // deprecated + PdbImplVC70 = 20000404, + PdbImplVC80 = 20030901, + PdbImplVC110 = 20091201, + PdbImplVC140 = 20140508, +}; + +enum PdbRaw_DbiVer : uint32_t { + PdbDbiVC41 = 930803, + PdbDbiV50 = 19960307, + PdbDbiV60 = 19970606, + PdbDbiV70 = 19990903, + PdbDbiV110 = 20091201 +}; + +enum PdbRaw_TpiVer : uint32_t { + PdbTpiV40 = 19950410, + PdbTpiV41 = 19951122, + PdbTpiV50 = 19961031, + PdbTpiV70 = 19990903, + PdbTpiV80 = 20040203, +}; + +enum PdbRaw_DbiSecContribVer : uint32_t { + DbiSecContribVer60 = 0xeffe0000 + 19970605, + DbiSecContribV2 = 0xeffe0000 + 20140516 +}; + +enum SpecialStream : uint32_t { + // Stream 0 contains the copy of previous version of the MSF directory. + // We are not currently using it, but technically if we find the main + // MSF is corrupted, we could fallback to it. + OldMSFDirectory = 0, + + StreamPDB = 1, + StreamTPI = 2, + StreamDBI = 3, + StreamIPI = 4, +}; + +enum class DbgHeaderType : uint16_t { + FPO, + Exception, + Fixup, + OmapToSrc, + OmapFromSrc, + SectionHdr, + TokenRidMap, + Xdata, + Pdata, + NewFPO, + SectionHdrOrig, + Max +}; + +enum class OMFSegDescFlags : uint16_t { + Read = 1 << 0, // Segment is readable. + Write = 1 << 1, // Segment is writable. + Execute = 1 << 2, // Segment is executable. + AddressIs32Bit = 1 << 3, // Descriptor describes a 32-bit linear address. + IsSelector = 1 << 8, // Frame represents a selector. + IsAbsoluteAddress = 1 << 9, // Frame represents an absolute address. + IsGroup = 1 << 10 // If set, descriptor represents a group. +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_PDBRAWCONSTANTS_H diff --git a/include/llvm/DebugInfo/PDB/Raw/RawError.h b/include/llvm/DebugInfo/PDB/Raw/RawError.h new file mode 100644 index 000000000000..b0687cddbf48 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/RawError.h @@ -0,0 +1,49 @@ +//===- RawError.h - Error extensions for raw PDB implementation -*- 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_RAW_RAWERROR_H +#define LLVM_DEBUGINFO_PDB_RAW_RAWERROR_H + +#include "llvm/Support/Error.h" + +#include <string> + +namespace llvm { +namespace pdb { +enum class raw_error_code { + unspecified = 1, + feature_unsupported, + corrupt_file, + insufficient_buffer, + no_stream, + index_out_of_bounds, + invalid_block_address, + not_writable, + invalid_tpi_hash, +}; + +/// Base class for errors originating when parsing raw PDB files +class RawError : public ErrorInfo<RawError> { +public: + static char ID; + RawError(raw_error_code C); + RawError(const std::string &Context); + RawError(raw_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; + raw_error_code Code; +}; +} +} +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/RawSession.h b/include/llvm/DebugInfo/PDB/Raw/RawSession.h new file mode 100644 index 000000000000..73d281eab1a7 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/RawSession.h @@ -0,0 +1,75 @@ +//===- RawSession.h - Native implementation of IPDBSession ------*- 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_RAW_RAWSESSION_H +#define LLVM_DEBUGINFO_PDB_RAW_RAWSESSION_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class RawSession : public IPDBSession { +public: + explicit RawSession(std::unique_ptr<PDBFile> PdbFile); + ~RawSession() override; + + static Error createFromPdb(StringRef Path, + std::unique_ptr<IPDBSession> &Session); + static Error createFromExe(StringRef Path, + std::unique_ptr<IPDBSession> &Session); + + uint64_t getLoadAddress() const override; + void setLoadAddress(uint64_t Address) override; + std::unique_ptr<PDBSymbolExe> getGlobalScope() const override; + std::unique_ptr<PDBSymbol> getSymbolById(uint32_t SymbolId) const override; + + std::unique_ptr<PDBSymbol> + findSymbolByAddress(uint64_t Address, PDB_SymType Type) const override; + + std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbers(const PDBSymbolCompiland &Compiland, + const IPDBSourceFile &File) const override; + std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbersByAddress(uint64_t Address, uint32_t Length) const override; + + std::unique_ptr<IPDBEnumSourceFiles> + findSourceFiles(const PDBSymbolCompiland *Compiland, llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<IPDBSourceFile> + findOneSourceFile(const PDBSymbolCompiland *Compiland, + llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> + findCompilandsForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<PDBSymbolCompiland> + findOneCompilandForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<IPDBEnumSourceFiles> getAllSourceFiles() const override; + std::unique_ptr<IPDBEnumSourceFiles> getSourceFilesForCompiland( + const PDBSymbolCompiland &Compiland) const override; + std::unique_ptr<IPDBSourceFile> + getSourceFileById(uint32_t FileId) const override; + + std::unique_ptr<IPDBEnumDataStreams> getDebugStreams() const override; + + PDBFile &getPDBFile() { return *Pdb; } + const PDBFile &getPDBFile() const { return *Pdb; } + +private: + std::unique_ptr<PDBFile> Pdb; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/RawTypes.h b/include/llvm/DebugInfo/PDB/Raw/RawTypes.h new file mode 100644 index 000000000000..afcfe9405c0f --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/RawTypes.h @@ -0,0 +1,86 @@ +//===- RawTypes.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_PDB_RAW_RAWTYPES_H +#define LLVM_DEBUGINFO_PDB_RAW_RAWTYPES_H + +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace pdb { +// This struct is defined as "SO" in langapi/include/pdb.h. +struct SectionOffset { + support::ulittle32_t Off; + support::ulittle16_t Isect; + char Padding[2]; +}; + +// This is HRFile. +struct PSHashRecord { + support::ulittle32_t Off; // Offset in the symbol record stream + support::ulittle32_t CRef; +}; + +// This struct is defined as `SC` in include/dbicommon.h +struct SectionContrib { + support::ulittle16_t ISect; + char Padding[2]; + support::little32_t Off; + support::little32_t Size; + support::ulittle32_t Characteristics; + support::ulittle16_t Imod; + char Padding2[2]; + support::ulittle32_t DataCrc; + support::ulittle32_t RelocCrc; +}; + +// This struct is defined as `SC2` in include/dbicommon.h +struct SectionContrib2 { + // To guarantee SectionContrib2 is standard layout, we cannot use inheritance. + SectionContrib Base; + support::ulittle32_t ISectCoff; +}; + +// This corresponds to the `OMFSegMap` structure. +struct SecMapHeader { + support::ulittle16_t SecCount; // Number of segment descriptors in table + support::ulittle16_t SecCountLog; // Number of logical segment descriptors +}; + +// This corresponds to the `OMFSegMapDesc` structure. The definition is not +// present in the reference implementation, but the layout is derived from +// code that accesses the fields. +struct SecMapEntry { + support::ulittle16_t Flags; // Descriptor flags. See OMFSegDescFlags + support::ulittle16_t Ovl; // Logical overlay number. + support::ulittle16_t Group; // Group index into descriptor array. + support::ulittle16_t Frame; + support::ulittle16_t SecName; // Byte index of the segment or group name + // in the sstSegName table, or 0xFFFF. + support::ulittle16_t ClassName; // Byte index of the class name in the + // sstSegName table, or 0xFFFF. + support::ulittle32_t Offset; // Byte offset of the logical segment + // within the specified physical segment. + // If group is set in flags, offset is the + // offset of the group. + support::ulittle32_t SecByteLength; // Byte count of the segment or group. +}; + +// Used for serialized hash table in TPI stream. +// In the reference, it is an array of TI and cbOff pair. +struct TypeIndexOffset { + codeview::TypeIndex Type; + support::ulittle32_t Offset; +}; + +} // namespace pdb +} // namespace llvm + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h b/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h new file mode 100644 index 000000000000..685a23411a3b --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h @@ -0,0 +1,41 @@ +//===- SymbolStream.cpp - PDB Symbol Stream Access --------------*- 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_RAW_PDBSYMBOLSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBSYMBOLSTREAM_H + +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class SymbolStream { +public: + SymbolStream(std::unique_ptr<MappedBlockStream> Stream); + ~SymbolStream(); + Error reload(); + + iterator_range<codeview::CVSymbolArray::Iterator> + getSymbols(bool *HadError) const; + + Error commit(); + +private: + codeview::CVSymbolArray SymbolRecords; + std::unique_ptr<MappedBlockStream> Stream; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/TpiStream.h b/include/llvm/DebugInfo/PDB/Raw/TpiStream.h new file mode 100644 index 000000000000..4f36d70aabed --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/TpiStream.h @@ -0,0 +1,72 @@ +//===- TpiStream.cpp - PDB Type Info (TPI) Stream 2 Access ------*- 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_RAW_PDBTPISTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBTPISTREAM_H + +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/Support/raw_ostream.h" + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class TpiStream { + struct HeaderInfo; + +public: + TpiStream(const PDBFile &File, std::unique_ptr<MappedBlockStream> Stream); + ~TpiStream(); + Error reload(); + + PdbRaw_TpiVer getTpiVersion() const; + + uint32_t TypeIndexBegin() const; + uint32_t TypeIndexEnd() const; + uint32_t NumTypeRecords() const; + uint16_t getTypeHashStreamIndex() const; + uint16_t getTypeHashStreamAuxIndex() const; + + uint32_t getHashKeySize() const; + uint32_t NumHashBuckets() const; + codeview::FixedStreamArray<support::ulittle32_t> getHashValues() const; + codeview::FixedStreamArray<TypeIndexOffset> getTypeIndexOffsets() const; + codeview::FixedStreamArray<TypeIndexOffset> getHashAdjustments() const; + + iterator_range<codeview::CVTypeArray::Iterator> types(bool *HadError) const; + + Error commit(); + +private: + Error verifyHashValues(); + + const PDBFile &Pdb; + std::unique_ptr<MappedBlockStream> Stream; + + codeview::CVTypeArray TypeRecords; + + std::unique_ptr<MappedBlockStream> HashStream; + codeview::FixedStreamArray<support::ulittle32_t> HashValues; + codeview::FixedStreamArray<TypeIndexOffset> TypeIndexOffsets; + codeview::FixedStreamArray<TypeIndexOffset> HashAdjustments; + + const HeaderInfo *Header; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/Symbolize/DIPrinter.h b/include/llvm/DebugInfo/Symbolize/DIPrinter.h index 3098199bb4da..49f86eae01cf 100644 --- a/include/llvm/DebugInfo/Symbolize/DIPrinter.h +++ b/include/llvm/DebugInfo/Symbolize/DIPrinter.h @@ -31,7 +31,7 @@ class DIPrinter { int PrintSourceContext; void print(const DILineInfo &Info, bool Inlined); - void printContext(std::string FileName, int64_t Line); + void printContext(const std::string &FileName, int64_t Line); public: DIPrinter(raw_ostream &OS, bool PrintFunctionNames = true, diff --git a/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h b/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h index ff9cc808875d..e0bec6f6cf85 100644 --- a/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h +++ b/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h @@ -14,8 +14,6 @@ #define LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEMODULE_H #include "llvm/DebugInfo/DIContext.h" -#include <memory> -#include <string> namespace llvm { namespace object { diff --git a/include/llvm/DebugInfo/Symbolize/Symbolize.h b/include/llvm/DebugInfo/Symbolize/Symbolize.h index ec3ae002659c..9253adf7eedd 100644 --- a/include/llvm/DebugInfo/Symbolize/Symbolize.h +++ b/include/llvm/DebugInfo/Symbolize/Symbolize.h @@ -19,6 +19,7 @@ #include <map> #include <memory> #include <string> +#include <utility> namespace llvm { namespace symbolize { @@ -40,7 +41,7 @@ public: bool RelativeAddresses = false, std::string DefaultArch = "") : PrintFunctions(PrintFunctions), UseSymbolTable(UseSymbolTable), Demangle(Demangle), RelativeAddresses(RelativeAddresses), - DefaultArch(DefaultArch) {} + DefaultArch(std::move(DefaultArch)) {} }; LLVMSymbolizer(const Options &Opts = Options()) : Opts(Opts) {} @@ -48,12 +49,12 @@ public: flush(); } - ErrorOr<DILineInfo> symbolizeCode(const std::string &ModuleName, - uint64_t ModuleOffset); - ErrorOr<DIInliningInfo> symbolizeInlinedCode(const std::string &ModuleName, - uint64_t ModuleOffset); - ErrorOr<DIGlobal> symbolizeData(const std::string &ModuleName, - uint64_t ModuleOffset); + Expected<DILineInfo> symbolizeCode(const std::string &ModuleName, + uint64_t ModuleOffset); + Expected<DIInliningInfo> symbolizeInlinedCode(const std::string &ModuleName, + uint64_t ModuleOffset); + Expected<DIGlobal> symbolizeData(const std::string &ModuleName, + uint64_t ModuleOffset); void flush(); static std::string DemangleName(const std::string &Name, const SymbolizableModule *ModInfo); @@ -63,8 +64,13 @@ private: // corresponding debug info. These objects can be the same. typedef std::pair<ObjectFile*, ObjectFile*> ObjectPair; - ErrorOr<SymbolizableModule *> + /// Returns a SymbolizableModule or an error if loading debug info failed. + /// Only one attempt is made to load a module, and errors during loading are + /// only reported once. Subsequent calls to get module info for a module that + /// failed to load will return nullptr. + Expected<SymbolizableModule *> getOrCreateModuleInfo(const std::string &ModuleName); + ObjectFile *lookUpDsymFile(const std::string &Path, const MachOObjectFile *ExeObj, const std::string &ArchName); @@ -73,27 +79,27 @@ private: const std::string &ArchName); /// \brief Returns pair of pointers to object and debug object. - ErrorOr<ObjectPair> getOrCreateObjectPair(const std::string &Path, + Expected<ObjectPair> getOrCreateObjectPair(const std::string &Path, const std::string &ArchName); /// \brief Return a pointer to object file at specified path, for a specified /// architecture (e.g. if path refers to a Mach-O universal binary, only one /// object file from it will be returned). - ErrorOr<ObjectFile *> getOrCreateObject(const std::string &Path, + Expected<ObjectFile *> getOrCreateObject(const std::string &Path, const std::string &ArchName); - std::map<std::string, ErrorOr<std::unique_ptr<SymbolizableModule>>> Modules; + std::map<std::string, std::unique_ptr<SymbolizableModule>> Modules; /// \brief Contains cached results of getOrCreateObjectPair(). - std::map<std::pair<std::string, std::string>, ErrorOr<ObjectPair>> + std::map<std::pair<std::string, std::string>, ObjectPair> ObjectPairForPathArch; /// \brief Contains parsed binary for each path, or parsing error. - std::map<std::string, ErrorOr<OwningBinary<Binary>>> BinaryForPath; + std::map<std::string, OwningBinary<Binary>> BinaryForPath; /// \brief Parsed object file for path/architecture pair, where "path" refers /// to Mach-O universal binary. - std::map<std::pair<std::string, std::string>, ErrorOr<std::unique_ptr<ObjectFile>>> + std::map<std::pair<std::string, std::string>, std::unique_ptr<ObjectFile>> ObjectForUBPathAndArch; Options Opts; |