aboutsummaryrefslogtreecommitdiff
path: root/lib/DebugInfo
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-07-23 20:41:05 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-07-23 20:41:05 +0000
commit01095a5d43bbfde13731688ddcf6048ebb8b7721 (patch)
tree4def12e759965de927d963ac65840d663ef9d1ea /lib/DebugInfo
parentf0f4822ed4b66e3579e92a89f368f8fb860e218e (diff)
downloadsrc-vendor/llvm/llvm-release_39-r276489.tar.gz
src-vendor/llvm/llvm-release_39-r276489.zip
Vendor import of llvm release_39 branch r276489:vendor/llvm/llvm-release_39-r276489
Diffstat (limited to 'lib/DebugInfo')
-rw-r--r--lib/DebugInfo/CodeView/ByteStream.cpp79
-rw-r--r--lib/DebugInfo/CodeView/CMakeLists.txt13
-rw-r--r--lib/DebugInfo/CodeView/CVTypeVisitor.cpp123
-rw-r--r--lib/DebugInfo/CodeView/CodeViewError.cpp67
-rw-r--r--lib/DebugInfo/CodeView/EnumTables.cpp375
-rw-r--r--lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp141
-rw-r--r--lib/DebugInfo/CodeView/ListRecordBuilder.cpp87
-rw-r--r--lib/DebugInfo/CodeView/Makefile14
-rw-r--r--lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp27
-rw-r--r--lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp2
-rw-r--r--lib/DebugInfo/CodeView/ModuleSubstream.cpp42
-rw-r--r--lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp104
-rw-r--r--lib/DebugInfo/CodeView/RecordSerialization.cpp171
-rw-r--r--lib/DebugInfo/CodeView/StreamReader.cpp93
-rw-r--r--lib/DebugInfo/CodeView/StreamWriter.cpp77
-rw-r--r--lib/DebugInfo/CodeView/SymbolDumper.cpp642
-rw-r--r--lib/DebugInfo/CodeView/TypeDumper.cpp696
-rw-r--r--lib/DebugInfo/CodeView/TypeRecord.cpp572
-rw-r--r--lib/DebugInfo/CodeView/TypeRecordBuilder.cpp36
-rw-r--r--lib/DebugInfo/CodeView/TypeStreamMerger.cpp149
-rw-r--r--lib/DebugInfo/CodeView/TypeTableBuilder.cpp224
-rw-r--r--lib/DebugInfo/DWARF/DWARFContext.cpp112
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugFrame.cpp209
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugLine.cpp77
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugLoc.cpp1
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugMacro.cpp3
-rw-r--r--lib/DebugInfo/DWARF/DWARFUnit.cpp37
-rw-r--r--lib/DebugInfo/DWARF/Makefile14
-rw-r--r--lib/DebugInfo/DWARF/module.modulemap1
-rw-r--r--lib/DebugInfo/Makefile15
-rw-r--r--lib/DebugInfo/PDB/CMakeLists.txt28
-rw-r--r--lib/DebugInfo/PDB/DIA/DIADataStream.cpp2
-rw-r--r--lib/DebugInfo/PDB/DIA/DIAEnumDebugStreams.cpp1
-rw-r--r--lib/DebugInfo/PDB/DIA/DIAEnumLineNumbers.cpp1
-rw-r--r--lib/DebugInfo/PDB/DIA/DIAEnumSourceFiles.cpp1
-rw-r--r--lib/DebugInfo/PDB/DIA/DIAEnumSymbols.cpp1
-rw-r--r--lib/DebugInfo/PDB/DIA/DIAError.cpp59
-rw-r--r--lib/DebugInfo/PDB/DIA/DIALineNumber.cpp1
-rw-r--r--lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp51
-rw-r--r--lib/DebugInfo/PDB/DIA/DIASession.cpp204
-rw-r--r--lib/DebugInfo/PDB/DIA/DIASourceFile.cpp13
-rw-r--r--lib/DebugInfo/PDB/GenericError.cpp67
-rw-r--r--lib/DebugInfo/PDB/IPDBSourceFile.cpp1
-rw-r--r--lib/DebugInfo/PDB/LLVMBuild.txt2
-rw-r--r--lib/DebugInfo/PDB/Makefile14
-rw-r--r--lib/DebugInfo/PDB/PDB.cpp26
-rw-r--r--lib/DebugInfo/PDB/PDBContext.cpp30
-rw-r--r--lib/DebugInfo/PDB/PDBExtras.cpp252
-rw-r--r--lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymDumper.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbol.cpp2
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolBlock.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolCompiland.cpp20
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp7
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolCustom.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolData.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolExe.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolFunc.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolLabel.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolThunk.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolUnknown.cpp1
-rw-r--r--lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp1
-rw-r--r--lib/DebugInfo/PDB/Raw/DbiStream.cpp462
-rw-r--r--lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp81
-rw-r--r--lib/DebugInfo/PDB/Raw/EnumTables.cpp38
-rw-r--r--lib/DebugInfo/PDB/Raw/Hash.cpp131
-rw-r--r--lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp25
-rw-r--r--lib/DebugInfo/PDB/Raw/InfoStream.cpp90
-rw-r--r--lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp67
-rw-r--r--lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp310
-rw-r--r--lib/DebugInfo/PDB/Raw/ModInfo.cpp127
-rw-r--r--lib/DebugInfo/PDB/Raw/ModStream.cpp82
-rw-r--r--lib/DebugInfo/PDB/Raw/MsfBuilder.cpp279
-rw-r--r--lib/DebugInfo/PDB/Raw/MsfCommon.cpp48
-rw-r--r--lib/DebugInfo/PDB/Raw/NameHashTable.cpp104
-rw-r--r--lib/DebugInfo/PDB/Raw/NameMap.cpp213
-rw-r--r--lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp50
-rw-r--r--lib/DebugInfo/PDB/Raw/PDBFile.cpp365
-rw-r--r--lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp102
-rw-r--r--lib/DebugInfo/PDB/Raw/PublicsStream.cpp173
-rw-r--r--lib/DebugInfo/PDB/Raw/RawError.cpp67
-rw-r--r--lib/DebugInfo/PDB/Raw/RawSession.cpp146
-rw-r--r--lib/DebugInfo/PDB/Raw/SymbolStream.cpp46
-rw-r--r--lib/DebugInfo/PDB/Raw/TpiStream.cpp273
-rw-r--r--lib/DebugInfo/Symbolize/DIPrinter.cpp20
-rw-r--r--lib/DebugInfo/Symbolize/Makefile15
-rw-r--r--lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp18
-rw-r--r--lib/DebugInfo/Symbolize/Symbolize.cpp185
108 files changed, 7860 insertions, 674 deletions
diff --git a/lib/DebugInfo/CodeView/ByteStream.cpp b/lib/DebugInfo/CodeView/ByteStream.cpp
new file mode 100644
index 000000000000..2c43bc6958d2
--- /dev/null
+++ b/lib/DebugInfo/CodeView/ByteStream.cpp
@@ -0,0 +1,79 @@
+//===- ByteStream.cpp - Reads stream data from a byte sequence ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/ByteStream.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Src,
+ ArrayRef<uint8_t> Dest) {
+ return make_error<CodeViewError>(cv_error_code::operation_unsupported,
+ "ByteStream is immutable.");
+}
+
+static Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Src,
+ MutableArrayRef<uint8_t> Dest) {
+ if (Dest.size() < Src.size())
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ if (Offset > Src.size() - Dest.size())
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+
+ ::memcpy(Dest.data() + Offset, Src.data(), Src.size());
+ return Error::success();
+}
+
+template <bool Writable>
+Error ByteStream<Writable>::readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) const {
+ if (Offset > Data.size())
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ if (Data.size() < Size + Offset)
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ Buffer = Data.slice(Offset, Size);
+ return Error::success();
+}
+
+template <bool Writable>
+Error ByteStream<Writable>::readLongestContiguousChunk(
+ uint32_t Offset, ArrayRef<uint8_t> &Buffer) const {
+ if (Offset >= Data.size())
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ Buffer = Data.slice(Offset);
+ return Error::success();
+}
+
+template <bool Writable>
+Error ByteStream<Writable>::writeBytes(uint32_t Offset,
+ ArrayRef<uint8_t> Buffer) const {
+ return ::writeBytes(Offset, Buffer, Data);
+}
+
+template <bool Writable> uint32_t ByteStream<Writable>::getLength() const {
+ return Data.size();
+}
+
+template <bool Writable> Error ByteStream<Writable>::commit() const {
+ return Error::success();
+}
+
+template <bool Writable> StringRef ByteStream<Writable>::str() const {
+ const char *CharData = reinterpret_cast<const char *>(Data.data());
+ return StringRef(CharData, Data.size());
+}
+
+namespace llvm {
+namespace codeview {
+template class ByteStream<true>;
+template class ByteStream<false>;
+}
+}
diff --git a/lib/DebugInfo/CodeView/CMakeLists.txt b/lib/DebugInfo/CodeView/CMakeLists.txt
index cfa0e4d8b401..47297a9131ee 100644
--- a/lib/DebugInfo/CodeView/CMakeLists.txt
+++ b/lib/DebugInfo/CodeView/CMakeLists.txt
@@ -1,10 +1,23 @@
add_llvm_library(LLVMDebugInfoCodeView
+ ByteStream.cpp
+ CodeViewError.cpp
+ CVTypeVisitor.cpp
+ EnumTables.cpp
FieldListRecordBuilder.cpp
Line.cpp
ListRecordBuilder.cpp
MemoryTypeTableBuilder.cpp
MethodListRecordBuilder.cpp
+ ModuleSubstream.cpp
+ ModuleSubstreamVisitor.cpp
+ RecordSerialization.cpp
+ StreamReader.cpp
+ StreamWriter.cpp
+ SymbolDumper.cpp
+ TypeDumper.cpp
+ TypeRecord.cpp
TypeRecordBuilder.cpp
+ TypeStreamMerger.cpp
TypeTableBuilder.cpp
ADDITIONAL_HEADER_DIRS
diff --git a/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
new file mode 100644
index 000000000000..09f72214c52b
--- /dev/null
+++ b/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
@@ -0,0 +1,123 @@
+//===- CVTypeVisitor.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+template <typename T>
+static Error takeObject(ArrayRef<uint8_t> &Data, const T *&Res) {
+ if (Data.size() < sizeof(*Res))
+ return llvm::make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ Res = reinterpret_cast<const T *>(Data.data());
+ Data = Data.drop_front(sizeof(*Res));
+ return Error::success();
+}
+
+CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
+ : Callbacks(Callbacks) {}
+
+Error CVTypeVisitor::visitTypeRecord(const CVRecord<TypeLeafKind> &Record) {
+ ArrayRef<uint8_t> LeafData = Record.Data;
+ if (auto EC = Callbacks.visitTypeBegin(Record))
+ return EC;
+ switch (Record.Type) {
+ default:
+ if (auto EC = Callbacks.visitUnknownType(Record))
+ return EC;
+ break;
+ case LF_FIELDLIST:
+ if (auto EC = Callbacks.visitFieldListBegin(Record))
+ return EC;
+ if (auto EC = visitFieldList(Record))
+ return EC;
+ if (auto EC = Callbacks.visitFieldListEnd(Record))
+ return EC;
+ break;
+#define TYPE_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: { \
+ TypeRecordKind RK = static_cast<TypeRecordKind>(EnumName); \
+ auto Result = Name##Record::deserialize(RK, LeafData); \
+ if (Result.getError()) \
+ return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); \
+ if (auto EC = Callbacks.visit##Name(*Result)) \
+ return EC; \
+ break; \
+ }
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
+ TYPE_RECORD(EnumVal, EnumVal, AliasName)
+#define MEMBER_RECORD(EnumName, EnumVal, Name)
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+ }
+ if (auto EC = Callbacks.visitTypeEnd(Record))
+ return EC;
+ return Error::success();
+}
+
+/// Visits the type records in Data. Sets the error flag on parse failures.
+Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
+ for (const auto &I : Types) {
+ if (auto EC = visitTypeRecord(I))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CVTypeVisitor::skipPadding(ArrayRef<uint8_t> &Data) {
+ if (Data.empty())
+ return Error::success();
+ uint8_t Leaf = Data.front();
+ if (Leaf < LF_PAD0)
+ return Error::success();
+ // Leaf is greater than 0xf0. We should advance by the number of bytes in
+ // the low 4 bits.
+ unsigned BytesToAdvance = Leaf & 0x0F;
+ if (Data.size() < BytesToAdvance) {
+ return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Invalid padding bytes!");
+ }
+ Data = Data.drop_front(BytesToAdvance);
+ return Error::success();
+}
+
+/// Visits individual member records of a field list record. Member records do
+/// not describe their own length, and need special handling.
+Error CVTypeVisitor::visitFieldList(const CVRecord<TypeLeafKind> &Record) {
+ ArrayRef<uint8_t> RecordData = Record.Data;
+ while (!RecordData.empty()) {
+ const ulittle16_t *LeafPtr;
+ if (auto EC = takeObject(RecordData, LeafPtr))
+ return EC;
+ TypeLeafKind Leaf = TypeLeafKind(unsigned(*LeafPtr));
+ switch (Leaf) {
+ default:
+ // Field list records do not describe their own length, so we cannot
+ // continue parsing past an unknown member type.
+ if (auto EC = Callbacks.visitUnknownMember(Record))
+ return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: { \
+ TypeRecordKind RK = static_cast<TypeRecordKind>(EnumName); \
+ auto Result = Name##Record::deserialize(RK, RecordData); \
+ if (Result.getError()) \
+ return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); \
+ if (auto EC = Callbacks.visit##Name(*Result)) \
+ return EC; \
+ break; \
+ }
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
+ MEMBER_RECORD(EnumVal, EnumVal, AliasName)
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+ }
+ if (auto EC = skipPadding(RecordData))
+ return EC;
+ }
+ return Error::success();
+}
diff --git a/lib/DebugInfo/CodeView/CodeViewError.cpp b/lib/DebugInfo/CodeView/CodeViewError.cpp
new file mode 100644
index 000000000000..aad1d8b25cd0
--- /dev/null
+++ b/lib/DebugInfo/CodeView/CodeViewError.cpp
@@ -0,0 +1,67 @@
+//===- CodeViewError.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+// FIXME: This class is only here to support the transition to llvm::Error. It
+// will be removed once this transition is complete. Clients should prefer to
+// deal with the Error value directly, rather than converting to error_code.
+class CodeViewErrorCategory : public std::error_category {
+public:
+ const char *name() const LLVM_NOEXCEPT override { return "llvm.codeview"; }
+
+ std::string message(int Condition) const override {
+ switch (static_cast<cv_error_code>(Condition)) {
+ case cv_error_code::unspecified:
+ return "An unknown error has occurred.";
+ case cv_error_code::insufficient_buffer:
+ return "The buffer is not large enough to read the requested number of "
+ "bytes.";
+ case cv_error_code::corrupt_record:
+ return "The CodeView record is corrupted.";
+ case cv_error_code::operation_unsupported:
+ return "The requested operation is not supported.";
+ }
+ llvm_unreachable("Unrecognized cv_error_code");
+ }
+};
+} // end anonymous namespace
+
+static ManagedStatic<CodeViewErrorCategory> Category;
+
+char CodeViewError::ID = 0;
+
+CodeViewError::CodeViewError(cv_error_code C) : CodeViewError(C, "") {}
+
+CodeViewError::CodeViewError(const std::string &Context)
+ : CodeViewError(cv_error_code::unspecified, Context) {}
+
+CodeViewError::CodeViewError(cv_error_code C, const std::string &Context)
+ : Code(C) {
+ ErrMsg = "CodeView Error: ";
+ std::error_code EC = convertToErrorCode();
+ if (Code != cv_error_code::unspecified)
+ ErrMsg += EC.message() + " ";
+ if (!Context.empty())
+ ErrMsg += Context;
+}
+
+void CodeViewError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; }
+
+const std::string &CodeViewError::getErrorMessage() const { return ErrMsg; }
+
+std::error_code CodeViewError::convertToErrorCode() const {
+ return std::error_code(static_cast<int>(Code), *Category);
+}
diff --git a/lib/DebugInfo/CodeView/EnumTables.cpp b/lib/DebugInfo/CodeView/EnumTables.cpp
new file mode 100644
index 000000000000..d59271b2367e
--- /dev/null
+++ b/lib/DebugInfo/CodeView/EnumTables.cpp
@@ -0,0 +1,375 @@
+//===- EnumTables.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+
+using namespace llvm;
+using namespace codeview;
+
+#define CV_ENUM_CLASS_ENT(enum_class, enum) \
+ { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
+
+#define CV_ENUM_ENT(ns, enum) \
+ { #enum, ns::enum }
+
+static const EnumEntry<SymbolKind> SymbolTypeNames[] = {
+#define CV_SYMBOL(enum, val) {#enum, enum},
+#include "llvm/DebugInfo/CodeView/CVSymbolTypes.def"
+#undef CV_SYMBOL
+};
+
+static const EnumEntry<uint16_t> RegisterNames[] = {
+ CV_ENUM_CLASS_ENT(RegisterId, Unknown),
+ CV_ENUM_CLASS_ENT(RegisterId, VFrame),
+ CV_ENUM_CLASS_ENT(RegisterId, AL),
+ CV_ENUM_CLASS_ENT(RegisterId, CL),
+ CV_ENUM_CLASS_ENT(RegisterId, DL),
+ CV_ENUM_CLASS_ENT(RegisterId, BL),
+ CV_ENUM_CLASS_ENT(RegisterId, AH),
+ CV_ENUM_CLASS_ENT(RegisterId, CH),
+ CV_ENUM_CLASS_ENT(RegisterId, DH),
+ CV_ENUM_CLASS_ENT(RegisterId, BH),
+ CV_ENUM_CLASS_ENT(RegisterId, AX),
+ CV_ENUM_CLASS_ENT(RegisterId, CX),
+ CV_ENUM_CLASS_ENT(RegisterId, DX),
+ CV_ENUM_CLASS_ENT(RegisterId, BX),
+ CV_ENUM_CLASS_ENT(RegisterId, SP),
+ CV_ENUM_CLASS_ENT(RegisterId, BP),
+ CV_ENUM_CLASS_ENT(RegisterId, SI),
+ CV_ENUM_CLASS_ENT(RegisterId, DI),
+ CV_ENUM_CLASS_ENT(RegisterId, EAX),
+ CV_ENUM_CLASS_ENT(RegisterId, ECX),
+ CV_ENUM_CLASS_ENT(RegisterId, EDX),
+ CV_ENUM_CLASS_ENT(RegisterId, EBX),
+ CV_ENUM_CLASS_ENT(RegisterId, ESP),
+ CV_ENUM_CLASS_ENT(RegisterId, EBP),
+ CV_ENUM_CLASS_ENT(RegisterId, ESI),
+ CV_ENUM_CLASS_ENT(RegisterId, EDI),
+ CV_ENUM_CLASS_ENT(RegisterId, ES),
+ CV_ENUM_CLASS_ENT(RegisterId, CS),
+ CV_ENUM_CLASS_ENT(RegisterId, SS),
+ CV_ENUM_CLASS_ENT(RegisterId, DS),
+ CV_ENUM_CLASS_ENT(RegisterId, FS),
+ CV_ENUM_CLASS_ENT(RegisterId, GS),
+ CV_ENUM_CLASS_ENT(RegisterId, IP),
+ CV_ENUM_CLASS_ENT(RegisterId, RAX),
+ CV_ENUM_CLASS_ENT(RegisterId, RBX),
+ CV_ENUM_CLASS_ENT(RegisterId, RCX),
+ CV_ENUM_CLASS_ENT(RegisterId, RDX),
+ CV_ENUM_CLASS_ENT(RegisterId, RSI),
+ CV_ENUM_CLASS_ENT(RegisterId, RDI),
+ CV_ENUM_CLASS_ENT(RegisterId, RBP),
+ CV_ENUM_CLASS_ENT(RegisterId, RSP),
+ CV_ENUM_CLASS_ENT(RegisterId, R8),
+ CV_ENUM_CLASS_ENT(RegisterId, R9),
+ CV_ENUM_CLASS_ENT(RegisterId, R10),
+ CV_ENUM_CLASS_ENT(RegisterId, R11),
+ CV_ENUM_CLASS_ENT(RegisterId, R12),
+ CV_ENUM_CLASS_ENT(RegisterId, R13),
+ CV_ENUM_CLASS_ENT(RegisterId, R14),
+ CV_ENUM_CLASS_ENT(RegisterId, R15),
+};
+
+static const EnumEntry<uint8_t> ProcSymFlagNames[] = {
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasFP),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasIRET),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasFRET),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, IsNoReturn),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, IsUnreachable),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasCustomCallingConv),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, IsNoInline),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasOptimizedDebugInfo),
+};
+
+static const EnumEntry<uint16_t> LocalFlags[] = {
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsParameter),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAddressTaken),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsCompilerGenerated),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAggregate),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAggregated),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAliased),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAlias),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsReturnValue),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsOptimizedOut),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredGlobal),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredStatic),
+};
+
+static const EnumEntry<uint8_t> FrameCookieKinds[] = {
+ CV_ENUM_CLASS_ENT(FrameCookieKind, Copy),
+ CV_ENUM_CLASS_ENT(FrameCookieKind, XorStackPointer),
+ CV_ENUM_CLASS_ENT(FrameCookieKind, XorFramePointer),
+ CV_ENUM_CLASS_ENT(FrameCookieKind, XorR13),
+};
+
+static const EnumEntry<codeview::SourceLanguage> SourceLanguages[] = {
+ CV_ENUM_ENT(SourceLanguage, C), CV_ENUM_ENT(SourceLanguage, Cpp),
+ CV_ENUM_ENT(SourceLanguage, Fortran), CV_ENUM_ENT(SourceLanguage, Masm),
+ CV_ENUM_ENT(SourceLanguage, Pascal), CV_ENUM_ENT(SourceLanguage, Basic),
+ CV_ENUM_ENT(SourceLanguage, Cobol), CV_ENUM_ENT(SourceLanguage, Link),
+ CV_ENUM_ENT(SourceLanguage, Cvtres), CV_ENUM_ENT(SourceLanguage, Cvtpgd),
+ CV_ENUM_ENT(SourceLanguage, CSharp), CV_ENUM_ENT(SourceLanguage, VB),
+ CV_ENUM_ENT(SourceLanguage, ILAsm), CV_ENUM_ENT(SourceLanguage, Java),
+ CV_ENUM_ENT(SourceLanguage, JScript), CV_ENUM_ENT(SourceLanguage, MSIL),
+ CV_ENUM_ENT(SourceLanguage, HLSL),
+};
+
+static const EnumEntry<uint32_t> CompileSym2FlagNames[] = {
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, EC),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, NoDbgInfo),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, LTCG),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, NoDataAlign),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, ManagedPresent),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, SecurityChecks),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, HotPatch),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, CVTCIL),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, MSILModule),
+};
+
+static const EnumEntry<uint32_t> CompileSym3FlagNames[] = {
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, EC),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, NoDbgInfo),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, LTCG),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, NoDataAlign),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, ManagedPresent),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, SecurityChecks),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, HotPatch),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, CVTCIL),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, MSILModule),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, Sdl),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, PGO),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, Exp),
+};
+
+static const EnumEntry<uint32_t> FileChecksumNames[] = {
+ CV_ENUM_CLASS_ENT(FileChecksumKind, None),
+ CV_ENUM_CLASS_ENT(FileChecksumKind, MD5),
+ CV_ENUM_CLASS_ENT(FileChecksumKind, SHA1),
+ CV_ENUM_CLASS_ENT(FileChecksumKind, SHA256),
+};
+
+static const EnumEntry<unsigned> CPUTypeNames[] = {
+ CV_ENUM_CLASS_ENT(CPUType, Intel8080),
+ CV_ENUM_CLASS_ENT(CPUType, Intel8086),
+ CV_ENUM_CLASS_ENT(CPUType, Intel80286),
+ CV_ENUM_CLASS_ENT(CPUType, Intel80386),
+ CV_ENUM_CLASS_ENT(CPUType, Intel80486),
+ CV_ENUM_CLASS_ENT(CPUType, Pentium),
+ CV_ENUM_CLASS_ENT(CPUType, PentiumPro),
+ CV_ENUM_CLASS_ENT(CPUType, Pentium3),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS16),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS32),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS64),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSI),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSII),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSIII),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSIV),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSV),
+ CV_ENUM_CLASS_ENT(CPUType, M68000),
+ CV_ENUM_CLASS_ENT(CPUType, M68010),
+ CV_ENUM_CLASS_ENT(CPUType, M68020),
+ CV_ENUM_CLASS_ENT(CPUType, M68030),
+ CV_ENUM_CLASS_ENT(CPUType, M68040),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21164),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21164A),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21264),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21364),
+ CV_ENUM_CLASS_ENT(CPUType, PPC601),
+ CV_ENUM_CLASS_ENT(CPUType, PPC603),
+ CV_ENUM_CLASS_ENT(CPUType, PPC604),
+ CV_ENUM_CLASS_ENT(CPUType, PPC620),
+ CV_ENUM_CLASS_ENT(CPUType, PPCFP),
+ CV_ENUM_CLASS_ENT(CPUType, PPCBE),
+ CV_ENUM_CLASS_ENT(CPUType, SH3),
+ CV_ENUM_CLASS_ENT(CPUType, SH3E),
+ CV_ENUM_CLASS_ENT(CPUType, SH3DSP),
+ CV_ENUM_CLASS_ENT(CPUType, SH4),
+ CV_ENUM_CLASS_ENT(CPUType, SHMedia),
+ CV_ENUM_CLASS_ENT(CPUType, ARM3),
+ CV_ENUM_CLASS_ENT(CPUType, ARM4),
+ CV_ENUM_CLASS_ENT(CPUType, ARM4T),
+ CV_ENUM_CLASS_ENT(CPUType, ARM5),
+ CV_ENUM_CLASS_ENT(CPUType, ARM5T),
+ CV_ENUM_CLASS_ENT(CPUType, ARM6),
+ CV_ENUM_CLASS_ENT(CPUType, ARM_XMAC),
+ CV_ENUM_CLASS_ENT(CPUType, ARM_WMMX),
+ CV_ENUM_CLASS_ENT(CPUType, ARM7),
+ CV_ENUM_CLASS_ENT(CPUType, Omni),
+ CV_ENUM_CLASS_ENT(CPUType, Ia64),
+ CV_ENUM_CLASS_ENT(CPUType, Ia64_2),
+ CV_ENUM_CLASS_ENT(CPUType, CEE),
+ CV_ENUM_CLASS_ENT(CPUType, AM33),
+ CV_ENUM_CLASS_ENT(CPUType, M32R),
+ CV_ENUM_CLASS_ENT(CPUType, TriCore),
+ CV_ENUM_CLASS_ENT(CPUType, X64),
+ CV_ENUM_CLASS_ENT(CPUType, EBC),
+ CV_ENUM_CLASS_ENT(CPUType, Thumb),
+ CV_ENUM_CLASS_ENT(CPUType, ARMNT),
+ CV_ENUM_CLASS_ENT(CPUType, D3D11_Shader),
+};
+
+static const EnumEntry<uint32_t> FrameProcSymFlagNames[] = {
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasAlloca),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasSetJmp),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasLongJmp),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasInlineAssembly),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasExceptionHandling),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, MarkedInline),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasStructuredExceptionHandling),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, Naked),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, SecurityChecks),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, AsynchronousExceptionHandling),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, NoStackOrderingForSecurityChecks),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, Inlined),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, StrictSecurityChecks),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, SafeBuffers),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, ProfileGuidedOptimization),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, ValidProfileCounts),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, OptimizedForSpeed),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfg),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfw),
+};
+
+static const EnumEntry<uint32_t> ModuleSubstreamKindNames[] = {
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, None),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, Symbols),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, Lines),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, StringTable),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, FileChecksums),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, FrameData),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, InlineeLines),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, CrossScopeImports),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, CrossScopeExports),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, ILLines),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, FuncMDTokenMap),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, TypeMDTokenMap),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, MergedAssemblyInput),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, CoffSymbolRVA),
+};
+
+static const EnumEntry<uint16_t> ExportSymFlagNames[] = {
+ CV_ENUM_CLASS_ENT(ExportFlags, IsConstant),
+ CV_ENUM_CLASS_ENT(ExportFlags, IsData),
+ CV_ENUM_CLASS_ENT(ExportFlags, IsPrivate),
+ CV_ENUM_CLASS_ENT(ExportFlags, HasNoName),
+ CV_ENUM_CLASS_ENT(ExportFlags, HasExplicitOrdinal),
+ CV_ENUM_CLASS_ENT(ExportFlags, IsForwarder),
+};
+
+static const EnumEntry<uint8_t> ThunkOrdinalNames[] = {
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, Standard),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, ThisAdjustor),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, Vcall),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, Pcode),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, UnknownLoad),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, TrampIncremental),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, BranchIsland),
+};
+
+static const EnumEntry<uint16_t> TrampolineNames[] = {
+ CV_ENUM_CLASS_ENT(TrampolineType, TrampIncremental),
+ CV_ENUM_CLASS_ENT(TrampolineType, BranchIsland),
+};
+
+static const EnumEntry<COFF::SectionCharacteristics>
+ ImageSectionCharacteristicNames[] = {
+ CV_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NOLOAD),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_GPREL),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE)};
+
+namespace llvm {
+namespace codeview {
+ArrayRef<EnumEntry<SymbolKind>> getSymbolTypeNames() {
+ return makeArrayRef(SymbolTypeNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getRegisterNames() {
+ return makeArrayRef(RegisterNames);
+}
+
+ArrayRef<EnumEntry<uint8_t>> getProcSymFlagNames() {
+ return makeArrayRef(ProcSymFlagNames);
+}
+ArrayRef<EnumEntry<uint16_t>> getLocalFlagNames() {
+ return makeArrayRef(LocalFlags);
+}
+ArrayRef<EnumEntry<uint8_t>> getFrameCookieKindNames() {
+ return makeArrayRef(FrameCookieKinds);
+}
+ArrayRef<EnumEntry<SourceLanguage>> getSourceLanguageNames() {
+ return makeArrayRef(SourceLanguages);
+}
+ArrayRef<EnumEntry<uint32_t>> getCompileSym2FlagNames() {
+ return makeArrayRef(CompileSym2FlagNames);
+}
+ArrayRef<EnumEntry<uint32_t>> getCompileSym3FlagNames() {
+ return makeArrayRef(CompileSym3FlagNames);
+}
+ArrayRef<EnumEntry<uint32_t>> getFileChecksumNames() {
+ return makeArrayRef(FileChecksumNames);
+}
+ArrayRef<EnumEntry<unsigned>> getCPUTypeNames() {
+ return makeArrayRef(CPUTypeNames);
+}
+ArrayRef<EnumEntry<uint32_t>> getFrameProcSymFlagNames() {
+ return makeArrayRef(FrameProcSymFlagNames);
+}
+ArrayRef<EnumEntry<uint16_t>> getExportSymFlagNames() {
+ return makeArrayRef(ExportSymFlagNames);
+}
+ArrayRef<EnumEntry<uint32_t>> getModuleSubstreamKindNames() {
+ return makeArrayRef(ModuleSubstreamKindNames);
+}
+ArrayRef<EnumEntry<uint8_t>> getThunkOrdinalNames() {
+ return makeArrayRef(ThunkOrdinalNames);
+}
+ArrayRef<EnumEntry<uint16_t>> getTrampolineNames() {
+ return makeArrayRef(TrampolineNames);
+}
+ArrayRef<EnumEntry<COFF::SectionCharacteristics>>
+getImageSectionCharacteristicNames() {
+ return makeArrayRef(ImageSectionCharacteristicNames);
+}
+}
+}
diff --git a/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp b/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp
index 91b71cc4b119..5f229e3d9f94 100644
--- a/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp
+++ b/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp
@@ -15,151 +15,118 @@ using namespace codeview;
FieldListRecordBuilder::FieldListRecordBuilder()
: ListRecordBuilder(TypeRecordKind::FieldList) {}
-void FieldListRecordBuilder::writeBaseClass(MemberAccess Access, TypeIndex Type,
- uint64_t Offset) {
+void FieldListRecordBuilder::writeBaseClass(const BaseClassRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
Builder.writeTypeRecordKind(TypeRecordKind::BaseClass);
- Builder.writeUInt16(static_cast<uint16_t>(Access));
- Builder.writeTypeIndex(Type);
- Builder.writeEncodedUnsignedInteger(Offset);
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
+ Builder.writeTypeIndex(Record.getBaseType());
+ Builder.writeEncodedUnsignedInteger(Record.getBaseOffset());
finishSubRecord();
}
-void FieldListRecordBuilder::writeEnumerate(MemberAccess Access, uint64_t Value,
- StringRef Name) {
+void FieldListRecordBuilder::writeEnumerator(const EnumeratorRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- Builder.writeTypeRecordKind(TypeRecordKind::Enumerate);
- Builder.writeUInt16(static_cast<uint16_t>(Access));
- Builder.writeEncodedUnsignedInteger(Value);
- Builder.writeNullTerminatedString(Name);
+ Builder.writeTypeRecordKind(TypeRecordKind::Enumerator);
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
+ // FIXME: Handle full APInt such as __int128.
+ Builder.writeEncodedUnsignedInteger(Record.getValue().getZExtValue());
+ Builder.writeNullTerminatedString(Record.getName());
finishSubRecord();
}
-void FieldListRecordBuilder::writeMember(MemberAccess Access, TypeIndex Type,
- uint64_t Offset, StringRef Name) {
+void FieldListRecordBuilder::writeDataMember(const DataMemberRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- Builder.writeTypeRecordKind(TypeRecordKind::Member);
- Builder.writeUInt16(static_cast<uint16_t>(Access));
- Builder.writeTypeIndex(Type);
- Builder.writeEncodedUnsignedInteger(Offset);
- Builder.writeNullTerminatedString(Name);
+ Builder.writeTypeRecordKind(Record.getKind());
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
+ Builder.writeTypeIndex(Record.getType());
+ Builder.writeEncodedUnsignedInteger(Record.getFieldOffset());
+ Builder.writeNullTerminatedString(Record.getName());
finishSubRecord();
}
-void FieldListRecordBuilder::writeMethod(uint16_t OverloadCount,
- TypeIndex MethodList, StringRef Name) {
+void FieldListRecordBuilder::writeOverloadedMethod(
+ const OverloadedMethodRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- Builder.writeTypeRecordKind(TypeRecordKind::Method);
- Builder.writeUInt16(OverloadCount);
- Builder.writeTypeIndex(MethodList);
- Builder.writeNullTerminatedString(Name);
+ Builder.writeTypeRecordKind(TypeRecordKind::OverloadedMethod);
+ Builder.writeUInt16(Record.getNumOverloads());
+ Builder.writeTypeIndex(Record.getMethodList());
+ Builder.writeNullTerminatedString(Record.getName());
finishSubRecord();
}
-void FieldListRecordBuilder::writeOneMethod(
- MemberAccess Access, MethodKind Kind, MethodOptions Options, TypeIndex Type,
- int32_t VTableSlotOffset, StringRef Name) {
+void FieldListRecordBuilder::writeOneMethod(const OneMethodRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- uint16_t Flags = static_cast<uint16_t>(Access);
- Flags |= static_cast<uint16_t>(Kind) << MethodKindShift;
- Flags |= static_cast<uint16_t>(Options);
+ uint16_t Flags = static_cast<uint16_t>(Record.getAccess());
+ Flags |= static_cast<uint16_t>(Record.getKind()) << MethodKindShift;
+ Flags |= static_cast<uint16_t>(Record.getOptions());
Builder.writeTypeRecordKind(TypeRecordKind::OneMethod);
Builder.writeUInt16(Flags);
- Builder.writeTypeIndex(Type);
- switch (Kind) {
- case MethodKind::IntroducingVirtual:
- case MethodKind::PureIntroducingVirtual:
- assert(VTableSlotOffset >= 0);
- Builder.writeInt32(VTableSlotOffset);
- break;
-
- default:
- assert(VTableSlotOffset == -1);
- break;
+ Builder.writeTypeIndex(Record.getType());
+ if (Record.isIntroducingVirtual()) {
+ assert(Record.getVFTableOffset() >= 0);
+ Builder.writeInt32(Record.getVFTableOffset());
+ } else {
+ assert(Record.getVFTableOffset() == -1);
}
- Builder.writeNullTerminatedString(Name);
+ Builder.writeNullTerminatedString(Record.getName());
finishSubRecord();
}
-void FieldListRecordBuilder::writeOneMethod(const MethodInfo &Method,
- StringRef Name) {
- writeOneMethod(Method.getAccess(), Method.getKind(), Method.getOptions(),
- Method.getType(), Method.getVTableSlotOffset(), Name);
-}
-
-void FieldListRecordBuilder::writeNestedType(TypeIndex Type, StringRef Name) {
+void FieldListRecordBuilder::writeNestedType(const NestedTypeRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- Builder.writeTypeRecordKind(TypeRecordKind::NestedType);
+ Builder.writeTypeRecordKind(Record.getKind());
Builder.writeUInt16(0);
- Builder.writeTypeIndex(Type);
- Builder.writeNullTerminatedString(Name);
+ Builder.writeTypeIndex(Record.getNestedType());
+ Builder.writeNullTerminatedString(Record.getName());
finishSubRecord();
}
-void FieldListRecordBuilder::writeStaticMember(MemberAccess Access,
- TypeIndex Type, StringRef Name) {
+void FieldListRecordBuilder::writeStaticDataMember(
+ const StaticDataMemberRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- Builder.writeTypeRecordKind(TypeRecordKind::StaticMember);
- Builder.writeUInt16(static_cast<uint16_t>(Access));
- Builder.writeTypeIndex(Type);
- Builder.writeNullTerminatedString(Name);
+ Builder.writeTypeRecordKind(Record.getKind());
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
+ Builder.writeTypeIndex(Record.getType());
+ Builder.writeNullTerminatedString(Record.getName());
finishSubRecord();
}
-void FieldListRecordBuilder::writeIndirectVirtualBaseClass(
- MemberAccess Access, TypeIndex Type, TypeIndex VirtualBasePointerType,
- int64_t VirtualBasePointerOffset, uint64_t SlotIndex) {
- writeVirtualBaseClass(TypeRecordKind::IndirectVirtualBaseClass, Access, Type,
- VirtualBasePointerType, VirtualBasePointerOffset,
- SlotIndex);
-}
-
void FieldListRecordBuilder::writeVirtualBaseClass(
- MemberAccess Access, TypeIndex Type, TypeIndex VirtualBasePointerType,
- int64_t VirtualBasePointerOffset, uint64_t SlotIndex) {
- writeVirtualBaseClass(TypeRecordKind::VirtualBaseClass, Access, Type,
- VirtualBasePointerType, VirtualBasePointerOffset,
- SlotIndex);
-}
-
-void FieldListRecordBuilder::writeVirtualBaseClass(
- TypeRecordKind Kind, MemberAccess Access, TypeIndex Type,
- TypeIndex VirtualBasePointerType, int64_t VirtualBasePointerOffset,
- uint64_t SlotIndex) {
+ const VirtualBaseClassRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- Builder.writeTypeRecordKind(Kind);
- Builder.writeUInt16(static_cast<uint16_t>(Access));
- Builder.writeTypeIndex(Type);
- Builder.writeTypeIndex(VirtualBasePointerType);
- Builder.writeEncodedInteger(VirtualBasePointerOffset);
- Builder.writeEncodedUnsignedInteger(SlotIndex);
+ Builder.writeTypeRecordKind(Record.getKind());
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
+ Builder.writeTypeIndex(Record.getBaseType());
+ Builder.writeTypeIndex(Record.getVBPtrType());
+ Builder.writeEncodedInteger(Record.getVBPtrOffset());
+ Builder.writeEncodedUnsignedInteger(Record.getVTableIndex());
finishSubRecord();
}
-void FieldListRecordBuilder::writeVirtualFunctionTablePointer(TypeIndex Type) {
+void FieldListRecordBuilder::writeVFPtr(const VFPtrRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- Builder.writeTypeRecordKind(TypeRecordKind::VirtualFunctionTablePointer);
+ Builder.writeTypeRecordKind(TypeRecordKind::VFPtr);
Builder.writeUInt16(0);
- Builder.writeTypeIndex(Type);
+ Builder.writeTypeIndex(Record.getType());
finishSubRecord();
-} \ No newline at end of file
+}
diff --git a/lib/DebugInfo/CodeView/ListRecordBuilder.cpp b/lib/DebugInfo/CodeView/ListRecordBuilder.cpp
index 69c7e87330e6..eb79e8ac9a3f 100644
--- a/lib/DebugInfo/CodeView/ListRecordBuilder.cpp
+++ b/lib/DebugInfo/CodeView/ListRecordBuilder.cpp
@@ -7,25 +7,96 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/SmallString.h"
#include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
using namespace llvm;
using namespace codeview;
-ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind) : Builder(Kind) {}
+ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind)
+ : Kind(Kind), Builder(Kind) {}
+
+void ListRecordBuilder::writeListContinuation(const ListContinuationRecord &R) {
+ TypeRecordBuilder &Builder = getBuilder();
+
+ assert(getLastContinuationSize() < 65535 - 8 && "continuation won't fit");
+
+ Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
+ Builder.writeUInt16(0);
+ Builder.writeTypeIndex(R.getContinuationIndex());
+
+ // End the current segment manually so that nothing comes after the
+ // continuation.
+ ContinuationOffsets.push_back(Builder.size());
+ SubrecordStart = Builder.size();
+}
void ListRecordBuilder::finishSubRecord() {
- // The builder starts at offset 2 in the actual CodeView buffer, so add an
- // additional offset of 2 before computing the alignment.
- uint32_t Remainder = (Builder.size() + 2) % 4;
+ // The type table inserts a 16 bit size field before each list, so factor that
+ // into our alignment padding.
+ uint32_t Remainder =
+ (Builder.size() + 2 * (ContinuationOffsets.size() + 1)) % 4;
if (Remainder != 0) {
for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0;
--PaddingBytesLeft) {
- Builder.writeUInt8(0xf0 + PaddingBytesLeft);
+ Builder.writeUInt8(LF_PAD0 + PaddingBytesLeft);
}
}
- // TODO: Split the list into multiple records if it's longer than 64KB, using
- // a subrecord of TypeRecordKind::Index to chain the records together.
- assert(Builder.size() < 65536);
+ // Check if this subrecord makes the current segment not fit in 64K minus the
+ // space for a continuation record (8 bytes). If the segment does not fit,
+ // back up and insert a continuation record, sliding the current subrecord
+ // down.
+ if (getLastContinuationSize() > 65535 - 8) {
+ assert(SubrecordStart != 0 && "can't slide from the start!");
+ SmallString<128> SubrecordCopy(
+ Builder.str().slice(SubrecordStart, Builder.size()));
+ assert(SubrecordCopy.size() < 65530 && "subrecord is too large to slide!");
+ Builder.truncate(SubrecordStart);
+
+ // Write a placeholder continuation record.
+ Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
+ Builder.writeUInt16(0);
+ Builder.writeUInt32(0);
+ ContinuationOffsets.push_back(Builder.size());
+ assert(Builder.size() == SubrecordStart + 8 && "wrong continuation size");
+ assert(getLastContinuationSize() < 65535 && "segment too big");
+
+ // Start a new list record of the appropriate kind, and copy the previous
+ // subrecord into place.
+ Builder.writeTypeRecordKind(Kind);
+ Builder.writeBytes(SubrecordCopy);
+ }
+
+ SubrecordStart = Builder.size();
+}
+
+TypeIndex ListRecordBuilder::writeListRecord(TypeTableBuilder &Table) {
+ // Get the continuation segments as a reversed vector of StringRefs for
+ // convenience.
+ SmallVector<StringRef, 1> Segments;
+ StringRef Data = str();
+ size_t LastEnd = 0;
+ for (size_t SegEnd : ContinuationOffsets) {
+ Segments.push_back(Data.slice(LastEnd, SegEnd));
+ LastEnd = SegEnd;
+ }
+ Segments.push_back(Data.slice(LastEnd, Builder.size()));
+
+ // Pop the last record off and emit it directly.
+ StringRef LastRec = Segments.pop_back_val();
+ TypeIndex ContinuationIndex = Table.writeRecord(LastRec);
+
+ // Emit each record with a continuation in reverse order, so that each one
+ // references the previous record.
+ for (StringRef Rec : reverse(Segments)) {
+ assert(*reinterpret_cast<const ulittle16_t *>(Rec.data()) ==
+ unsigned(Kind));
+ ulittle32_t *ContinuationPtr =
+ reinterpret_cast<ulittle32_t *>(const_cast<char *>(Rec.end())) - 1;
+ *ContinuationPtr = ContinuationIndex.getIndex();
+ ContinuationIndex = Table.writeRecord(Rec);
+ }
+ return ContinuationIndex;
}
diff --git a/lib/DebugInfo/CodeView/Makefile b/lib/DebugInfo/CodeView/Makefile
deleted file mode 100644
index 535bc10b7442..000000000000
--- a/lib/DebugInfo/CodeView/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-##===- lib/DebugInfo/CodeView/Makefile ---------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../../..
-LIBRARYNAME = LLVMDebugInfoCodeView
-BUILD_ARCHIVE := 1
-
-include $(LEVEL)/Makefile.common
diff --git a/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp b/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp
index 9afce92eeb1d..8b9e73b94ff5 100644
--- a/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp
+++ b/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp
@@ -13,23 +13,34 @@
using namespace llvm;
using namespace codeview;
-MemoryTypeTableBuilder::Record::Record(StringRef RData)
- : Size(RData.size()), Data(new char[RData.size()]) {
- memcpy(Data.get(), RData.data(), RData.size());
-}
-
TypeIndex MemoryTypeTableBuilder::writeRecord(StringRef Data) {
+ assert(Data.size() <= UINT16_MAX);
auto I = HashedRecords.find(Data);
if (I != HashedRecords.end()) {
return I->second;
}
- std::unique_ptr<Record> R(new Record(Data));
+ // The record provided by the user lacks the 2 byte size field prefix and is
+ // not padded to 4 bytes. Ultimately, that is what gets emitted in the object
+ // file, so pad it out now.
+ const int SizeOfRecLen = 2;
+ const int Align = 4;
+ int TotalSize = alignTo(Data.size() + SizeOfRecLen, Align);
+ assert(TotalSize - SizeOfRecLen <= UINT16_MAX);
+ char *Mem =
+ reinterpret_cast<char *>(RecordStorage.Allocate(TotalSize, Align));
+ *reinterpret_cast<ulittle16_t *>(Mem) = uint16_t(TotalSize - SizeOfRecLen);
+ memcpy(Mem + SizeOfRecLen, Data.data(), Data.size());
+ for (int I = Data.size() + SizeOfRecLen; I < TotalSize; ++I)
+ Mem[I] = LF_PAD0 + (TotalSize - I);
TypeIndex TI(static_cast<uint32_t>(Records.size()) +
TypeIndex::FirstNonSimpleIndex);
- HashedRecords.insert(std::make_pair(StringRef(R->data(), R->size()), TI));
- Records.push_back(std::move(R));
+
+ // Use only the data supplied by the user as a key to the hash table, so that
+ // future lookups will succeed.
+ HashedRecords.insert(std::make_pair(StringRef(Mem + SizeOfRecLen, Data.size()), TI));
+ Records.push_back(StringRef(Mem, TotalSize));
return TI;
}
diff --git a/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp b/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp
index 889302556b2d..ae089a352081 100644
--- a/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp
+++ b/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp
@@ -14,7 +14,7 @@ using namespace llvm;
using namespace codeview;
MethodListRecordBuilder::MethodListRecordBuilder()
- : ListRecordBuilder(TypeRecordKind::MethodList) {}
+ : ListRecordBuilder(TypeRecordKind::MethodOverloadList) {}
void MethodListRecordBuilder::writeMethod(MemberAccess Access, MethodKind Kind,
MethodOptions Options, TypeIndex Type,
diff --git a/lib/DebugInfo/CodeView/ModuleSubstream.cpp b/lib/DebugInfo/CodeView/ModuleSubstream.cpp
new file mode 100644
index 000000000000..2e31ed6b5b7f
--- /dev/null
+++ b/lib/DebugInfo/CodeView/ModuleSubstream.cpp
@@ -0,0 +1,42 @@
+//===- ModuleSubstream.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/ModuleSubstream.h"
+
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+ModuleSubstream::ModuleSubstream() : Kind(ModuleSubstreamKind::None) {}
+
+ModuleSubstream::ModuleSubstream(ModuleSubstreamKind Kind, StreamRef Data)
+ : Kind(Kind), Data(Data) {}
+
+Error ModuleSubstream::initialize(StreamRef Stream, ModuleSubstream &Info) {
+ const ModuleSubsectionHeader *Header;
+ StreamReader Reader(Stream);
+ if (auto EC = Reader.readObject(Header))
+ return EC;
+
+ ModuleSubstreamKind Kind =
+ static_cast<ModuleSubstreamKind>(uint32_t(Header->Kind));
+ if (auto EC = Reader.readStreamRef(Info.Data, Header->Length))
+ return EC;
+ Info.Kind = Kind;
+ return Error::success();
+}
+
+uint32_t ModuleSubstream::getRecordLength() const {
+ return sizeof(ModuleSubsectionHeader) + Data.getLength();
+}
+
+ModuleSubstreamKind ModuleSubstream::getSubstreamKind() const { return Kind; }
+
+StreamRef ModuleSubstream::getRecordData() const { return Data; }
diff --git a/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp b/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp
new file mode 100644
index 000000000000..6f237ee67fe4
--- /dev/null
+++ b/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp
@@ -0,0 +1,104 @@
+//===- ModuleSubstreamVisitor.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error IModuleSubstreamVisitor::visitSymbols(StreamRef Data) {
+ return visitUnknown(ModuleSubstreamKind::Symbols, Data);
+}
+Error IModuleSubstreamVisitor::visitLines(StreamRef Data,
+ const LineSubstreamHeader *Header,
+ const LineInfoArray &Lines) {
+ return visitUnknown(ModuleSubstreamKind::Lines, Data);
+}
+Error IModuleSubstreamVisitor::visitStringTable(StreamRef Data) {
+ return visitUnknown(ModuleSubstreamKind::StringTable, Data);
+}
+Error IModuleSubstreamVisitor::visitFileChecksums(
+ StreamRef Data, const FileChecksumArray &Checksums) {
+ return visitUnknown(ModuleSubstreamKind::FileChecksums, Data);
+}
+Error IModuleSubstreamVisitor::visitFrameData(StreamRef Data) {
+ return visitUnknown(ModuleSubstreamKind::FrameData, Data);
+}
+Error IModuleSubstreamVisitor::visitInlineeLines(StreamRef Data) {
+ return visitUnknown(ModuleSubstreamKind::InlineeLines, Data);
+}
+Error IModuleSubstreamVisitor::visitCrossScopeImports(StreamRef Data) {
+ return visitUnknown(ModuleSubstreamKind::CrossScopeExports, Data);
+}
+Error IModuleSubstreamVisitor::visitCrossScopeExports(StreamRef Data) {
+ return visitUnknown(ModuleSubstreamKind::CrossScopeImports, Data);
+}
+Error IModuleSubstreamVisitor::visitILLines(StreamRef Data) {
+ return visitUnknown(ModuleSubstreamKind::ILLines, Data);
+}
+Error IModuleSubstreamVisitor::visitFuncMDTokenMap(StreamRef Data) {
+ return visitUnknown(ModuleSubstreamKind::FuncMDTokenMap, Data);
+}
+Error IModuleSubstreamVisitor::visitTypeMDTokenMap(StreamRef Data) {
+ return visitUnknown(ModuleSubstreamKind::TypeMDTokenMap, Data);
+}
+Error IModuleSubstreamVisitor::visitMergedAssemblyInput(StreamRef Data) {
+ return visitUnknown(ModuleSubstreamKind::MergedAssemblyInput, Data);
+}
+Error IModuleSubstreamVisitor::visitCoffSymbolRVA(StreamRef Data) {
+ return visitUnknown(ModuleSubstreamKind::CoffSymbolRVA, Data);
+}
+
+Error llvm::codeview::visitModuleSubstream(const ModuleSubstream &R,
+ IModuleSubstreamVisitor &V) {
+ switch (R.getSubstreamKind()) {
+ case ModuleSubstreamKind::Symbols:
+ return V.visitSymbols(R.getRecordData());
+ case ModuleSubstreamKind::Lines: {
+ StreamReader Reader(R.getRecordData());
+ const LineSubstreamHeader *Header;
+ if (auto EC = Reader.readObject(Header))
+ return EC;
+ VarStreamArrayExtractor<LineColumnEntry> E(Header);
+ LineInfoArray LineInfos(E);
+ if (auto EC = Reader.readArray(LineInfos, Reader.bytesRemaining()))
+ return EC;
+ return V.visitLines(R.getRecordData(), Header, LineInfos);
+ }
+ case ModuleSubstreamKind::StringTable:
+ return V.visitStringTable(R.getRecordData());
+ case ModuleSubstreamKind::FileChecksums: {
+ StreamReader Reader(R.getRecordData());
+ FileChecksumArray Checksums;
+ if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining()))
+ return EC;
+ return V.visitFileChecksums(R.getRecordData(), Checksums);
+ }
+ case ModuleSubstreamKind::FrameData:
+ return V.visitFrameData(R.getRecordData());
+ case ModuleSubstreamKind::InlineeLines:
+ return V.visitInlineeLines(R.getRecordData());
+ case ModuleSubstreamKind::CrossScopeImports:
+ return V.visitCrossScopeImports(R.getRecordData());
+ case ModuleSubstreamKind::CrossScopeExports:
+ return V.visitCrossScopeExports(R.getRecordData());
+ case ModuleSubstreamKind::ILLines:
+ return V.visitILLines(R.getRecordData());
+ case ModuleSubstreamKind::FuncMDTokenMap:
+ return V.visitFuncMDTokenMap(R.getRecordData());
+ case ModuleSubstreamKind::TypeMDTokenMap:
+ return V.visitTypeMDTokenMap(R.getRecordData());
+ case ModuleSubstreamKind::MergedAssemblyInput:
+ return V.visitMergedAssemblyInput(R.getRecordData());
+ case ModuleSubstreamKind::CoffSymbolRVA:
+ return V.visitCoffSymbolRVA(R.getRecordData());
+ default:
+ return V.visitUnknown(R.getSubstreamKind(), R.getRecordData());
+ }
+}
diff --git a/lib/DebugInfo/CodeView/RecordSerialization.cpp b/lib/DebugInfo/CodeView/RecordSerialization.cpp
new file mode 100644
index 000000000000..ab9206a33ec0
--- /dev/null
+++ b/lib/DebugInfo/CodeView/RecordSerialization.cpp
@@ -0,0 +1,171 @@
+//===-- RecordSerialization.cpp -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Utilities for serializing and deserializing CodeView records.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::support;
+
+/// 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 llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
+ return StringRef(reinterpret_cast<const char *>(LeafData.data()),
+ LeafData.size());
+}
+
+StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
+ return getBytesAsCharacters(LeafData).split('\0').first;
+}
+
+std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data, APSInt &Num) {
+ // Used to avoid overload ambiguity on APInt construtor.
+ bool FalseVal = false;
+ if (Data.size() < 2)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ uint16_t Short = *reinterpret_cast<const ulittle16_t *>(Data.data());
+ Data = Data.drop_front(2);
+ if (Short < LF_NUMERIC) {
+ Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false),
+ /*isUnsigned=*/true);
+ return std::error_code();
+ }
+ switch (Short) {
+ case LF_CHAR:
+ if (Data.size() < 1)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = APSInt(APInt(/*numBits=*/8,
+ *reinterpret_cast<const int8_t *>(Data.data()),
+ /*isSigned=*/true),
+ /*isUnsigned=*/false);
+ Data = Data.drop_front(1);
+ return std::error_code();
+ case LF_SHORT:
+ if (Data.size() < 2)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = APSInt(APInt(/*numBits=*/16,
+ *reinterpret_cast<const little16_t *>(Data.data()),
+ /*isSigned=*/true),
+ /*isUnsigned=*/false);
+ Data = Data.drop_front(2);
+ return std::error_code();
+ case LF_USHORT:
+ if (Data.size() < 2)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = APSInt(APInt(/*numBits=*/16,
+ *reinterpret_cast<const ulittle16_t *>(Data.data()),
+ /*isSigned=*/false),
+ /*isUnsigned=*/true);
+ Data = Data.drop_front(2);
+ return std::error_code();
+ case LF_LONG:
+ if (Data.size() < 4)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = APSInt(APInt(/*numBits=*/32,
+ *reinterpret_cast<const little32_t *>(Data.data()),
+ /*isSigned=*/true),
+ /*isUnsigned=*/false);
+ Data = Data.drop_front(4);
+ return std::error_code();
+ case LF_ULONG:
+ if (Data.size() < 4)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = APSInt(APInt(/*numBits=*/32,
+ *reinterpret_cast<const ulittle32_t *>(Data.data()),
+ /*isSigned=*/FalseVal),
+ /*isUnsigned=*/true);
+ Data = Data.drop_front(4);
+ return std::error_code();
+ case LF_QUADWORD:
+ if (Data.size() < 8)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = APSInt(APInt(/*numBits=*/64,
+ *reinterpret_cast<const little64_t *>(Data.data()),
+ /*isSigned=*/true),
+ /*isUnsigned=*/false);
+ Data = Data.drop_front(8);
+ return std::error_code();
+ case LF_UQUADWORD:
+ if (Data.size() < 8)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = APSInt(APInt(/*numBits=*/64,
+ *reinterpret_cast<const ulittle64_t *>(Data.data()),
+ /*isSigned=*/false),
+ /*isUnsigned=*/true);
+ Data = Data.drop_front(8);
+ return std::error_code();
+ }
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+}
+
+std::error_code llvm::codeview::consume(StringRef &Data, APSInt &Num) {
+ ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
+ auto EC = consume(Bytes, Num);
+ Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
+ return EC;
+}
+
+/// Decode a numeric leaf value that is known to be a uint64_t.
+std::error_code llvm::codeview::consume_numeric(ArrayRef<uint8_t> &Data,
+ uint64_t &Num) {
+ APSInt N;
+ if (auto EC = consume(Data, N))
+ return EC;
+ if (N.isSigned() || !N.isIntN(64))
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = N.getLimitedValue();
+ return std::error_code();
+}
+
+std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
+ uint32_t &Item) {
+ const support::ulittle32_t *IntPtr;
+ if (auto EC = consumeObject(Data, IntPtr))
+ return EC;
+ Item = *IntPtr;
+ return std::error_code();
+}
+
+std::error_code llvm::codeview::consume(StringRef &Data, uint32_t &Item) {
+ ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
+ auto EC = consume(Bytes, Item);
+ Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
+ return EC;
+}
+
+std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
+ int32_t &Item) {
+ const support::little32_t *IntPtr;
+ if (auto EC = consumeObject(Data, IntPtr))
+ return EC;
+ Item = *IntPtr;
+ return std::error_code();
+}
+
+std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
+ StringRef &Item) {
+ if (Data.empty())
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ StringRef Rest;
+ std::tie(Item, Rest) = getBytesAsCharacters(Data).split('\0');
+ // We expect this to be null terminated. If it was not, it is an error.
+ if (Data.size() == Item.size())
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ Data = ArrayRef<uint8_t>(Rest.bytes_begin(), Rest.bytes_end());
+ return std::error_code();
+}
diff --git a/lib/DebugInfo/CodeView/StreamReader.cpp b/lib/DebugInfo/CodeView/StreamReader.cpp
new file mode 100644
index 000000000000..64e45487322e
--- /dev/null
+++ b/lib/DebugInfo/CodeView/StreamReader.cpp
@@ -0,0 +1,93 @@
+//===- StreamReader.cpp - Reads bytes and objects from a stream -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/StreamRef.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+StreamReader::StreamReader(StreamRef S) : Stream(S), Offset(0) {}
+
+Error StreamReader::readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer) {
+ if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer))
+ return EC;
+ Offset += Buffer.size();
+ return Error::success();
+}
+
+Error StreamReader::readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size) {
+ if (auto EC = Stream.readBytes(Offset, Size, Buffer))
+ return EC;
+ Offset += Size;
+ return Error::success();
+}
+
+Error StreamReader::readInteger(uint16_t &Dest) {
+ const support::ulittle16_t *P;
+ if (auto EC = readObject(P))
+ return EC;
+ Dest = *P;
+ return Error::success();
+}
+
+Error StreamReader::readInteger(uint32_t &Dest) {
+ const support::ulittle32_t *P;
+ if (auto EC = readObject(P))
+ return EC;
+ Dest = *P;
+ return Error::success();
+}
+
+Error StreamReader::readZeroString(StringRef &Dest) {
+ uint32_t Length = 0;
+ // First compute the length of the string by reading 1 byte at a time.
+ uint32_t OriginalOffset = getOffset();
+ const char *C;
+ do {
+ if (auto EC = readObject(C))
+ return EC;
+ if (*C != '\0')
+ ++Length;
+ } while (*C != '\0');
+ // Now go back and request a reference for that many bytes.
+ uint32_t NewOffset = getOffset();
+ setOffset(OriginalOffset);
+
+ ArrayRef<uint8_t> Data;
+ if (auto EC = readBytes(Data, Length))
+ return EC;
+ Dest = StringRef(reinterpret_cast<const char *>(Data.begin()), Data.size());
+
+ // Now set the offset back to where it was after we calculated the length.
+ setOffset(NewOffset);
+ return Error::success();
+}
+
+Error StreamReader::readFixedString(StringRef &Dest, uint32_t Length) {
+ ArrayRef<uint8_t> Bytes;
+ if (auto EC = readBytes(Bytes, Length))
+ return EC;
+ Dest = StringRef(reinterpret_cast<const char *>(Bytes.begin()), Bytes.size());
+ return Error::success();
+}
+
+Error StreamReader::readStreamRef(StreamRef &Ref) {
+ return readStreamRef(Ref, bytesRemaining());
+}
+
+Error StreamReader::readStreamRef(StreamRef &Ref, uint32_t Length) {
+ if (bytesRemaining() < Length)
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ Ref = Stream.slice(Offset, Length);
+ Offset += Length;
+ return Error::success();
+}
diff --git a/lib/DebugInfo/CodeView/StreamWriter.cpp b/lib/DebugInfo/CodeView/StreamWriter.cpp
new file mode 100644
index 000000000000..f61c6b522f57
--- /dev/null
+++ b/lib/DebugInfo/CodeView/StreamWriter.cpp
@@ -0,0 +1,77 @@
+//===- StreamWrite.cpp - Writes bytes and objects to a stream -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/StreamWriter.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/CodeView/StreamRef.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+StreamWriter::StreamWriter(StreamRef S) : Stream(S), Offset(0) {}
+
+Error StreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) {
+ if (auto EC = Stream.writeBytes(Offset, Buffer))
+ return EC;
+ Offset += Buffer.size();
+ return Error::success();
+}
+
+Error StreamWriter::writeInteger(uint16_t Int) {
+ return writeObject(support::ulittle16_t(Int));
+}
+
+Error StreamWriter::writeInteger(uint32_t Int) {
+ return writeObject(support::ulittle32_t(Int));
+}
+
+Error StreamWriter::writeZeroString(StringRef Str) {
+ if (auto EC = writeFixedString(Str))
+ return EC;
+ if (auto EC = writeObject('\0'))
+ return EC;
+
+ return Error::success();
+}
+
+Error StreamWriter::writeFixedString(StringRef Str) {
+ ArrayRef<uint8_t> Bytes(Str.bytes_begin(), Str.bytes_end());
+ if (auto EC = Stream.writeBytes(Offset, Bytes))
+ return EC;
+
+ Offset += Str.size();
+ return Error::success();
+}
+
+Error StreamWriter::writeStreamRef(StreamRef Ref) {
+ if (auto EC = writeStreamRef(Ref, Ref.getLength()))
+ return EC;
+ Offset += Ref.getLength();
+ return Error::success();
+}
+
+Error StreamWriter::writeStreamRef(StreamRef Ref, uint32_t Length) {
+ Ref = Ref.slice(0, Length);
+
+ StreamReader SrcReader(Ref);
+ // This is a bit tricky. If we just call readBytes, we are requiring that it
+ // return us the entire stream as a contiguous buffer. For large streams this
+ // will allocate a huge amount of space from the pool. Instead, iterate over
+ // each contiguous chunk until we've consumed the entire stream.
+ while (SrcReader.bytesRemaining() > 0) {
+ ArrayRef<uint8_t> Chunk;
+ if (auto EC = SrcReader.readLongestContiguousChunk(Chunk))
+ return EC;
+ if (auto EC = writeBytes(Chunk))
+ return EC;
+ }
+ return Error::success();
+}
diff --git a/lib/DebugInfo/CodeView/SymbolDumper.cpp b/lib/DebugInfo/CodeView/SymbolDumper.cpp
new file mode 100644
index 000000000000..6763c3d562d7
--- /dev/null
+++ b/lib/DebugInfo/CodeView/SymbolDumper.cpp
@@ -0,0 +1,642 @@
+//===-- SymbolDumper.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeDumper.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+#include <system_error>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+/// Use this private dumper implementation to keep implementation details about
+/// the visitor out of SymbolDumper.h.
+class CVSymbolDumperImpl : public CVSymbolVisitor<CVSymbolDumperImpl> {
+public:
+ CVSymbolDumperImpl(CVTypeDumper &CVTD, SymbolDumpDelegate *ObjDelegate,
+ ScopedPrinter &W, bool PrintRecordBytes)
+ : CVSymbolVisitor(ObjDelegate), CVTD(CVTD), ObjDelegate(ObjDelegate),
+ W(W), PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {}
+
+/// CVSymbolVisitor overrides.
+#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
+ void visit##Name(SymbolKind Kind, Name &Record);
+#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CVSymbolTypes.def"
+
+ void visitSymbolBegin(SymbolKind Kind, ArrayRef<uint8_t> Data);
+ void visitSymbolEnd(SymbolKind Kind, ArrayRef<uint8_t> OriginalSymData);
+ void visitUnknownSymbol(SymbolKind Kind, ArrayRef<uint8_t> Data);
+
+private:
+ void printLocalVariableAddrRange(const LocalVariableAddrRange &Range,
+ uint32_t RelocationOffset);
+ void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps);
+
+ CVTypeDumper &CVTD;
+ SymbolDumpDelegate *ObjDelegate;
+ ScopedPrinter &W;
+
+ bool PrintRecordBytes;
+ bool InFunctionScope;
+};
+}
+
+void CVSymbolDumperImpl::printLocalVariableAddrRange(
+ const LocalVariableAddrRange &Range, uint32_t RelocationOffset) {
+ DictScope S(W, "LocalVariableAddrRange");
+ if (ObjDelegate)
+ ObjDelegate->printRelocatedField("OffsetStart", RelocationOffset,
+ Range.OffsetStart);
+ W.printHex("ISectStart", Range.ISectStart);
+ W.printHex("Range", Range.Range);
+}
+
+void CVSymbolDumperImpl::printLocalVariableAddrGap(
+ ArrayRef<LocalVariableAddrGap> Gaps) {
+ for (auto &Gap : Gaps) {
+ ListScope S(W, "LocalVariableAddrGap");
+ W.printHex("GapStartOffset", Gap.GapStartOffset);
+ W.printHex("Range", Gap.Range);
+ }
+}
+
+void CVSymbolDumperImpl::visitSymbolBegin(SymbolKind Kind,
+ ArrayRef<uint8_t> Data) {}
+
+void CVSymbolDumperImpl::visitSymbolEnd(SymbolKind Kind,
+ ArrayRef<uint8_t> OriginalSymData) {
+ if (PrintRecordBytes && ObjDelegate)
+ ObjDelegate->printBinaryBlockWithRelocs("SymData", OriginalSymData);
+}
+
+void CVSymbolDumperImpl::visitBlockSym(SymbolKind Kind, BlockSym &Block) {
+ DictScope S(W, "BlockStart");
+
+ StringRef LinkageName;
+ W.printHex("PtrParent", Block.Header.PtrParent);
+ W.printHex("PtrEnd", Block.Header.PtrEnd);
+ W.printHex("CodeSize", Block.Header.CodeSize);
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset", Block.getRelocationOffset(),
+ Block.Header.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", Block.Header.Segment);
+ W.printString("BlockName", Block.Name);
+ W.printString("LinkageName", LinkageName);
+}
+
+void CVSymbolDumperImpl::visitThunk32Sym(SymbolKind Kind, Thunk32Sym &Thunk) {
+ DictScope S(W, "Thunk32");
+ W.printNumber("Parent", Thunk.Header.Parent);
+ W.printNumber("End", Thunk.Header.End);
+ W.printNumber("Next", Thunk.Header.Next);
+ W.printNumber("Off", Thunk.Header.Off);
+ W.printNumber("Seg", Thunk.Header.Seg);
+ W.printNumber("Len", Thunk.Header.Len);
+ W.printEnum("Ordinal", Thunk.Header.Ord, getThunkOrdinalNames());
+}
+
+void CVSymbolDumperImpl::visitTrampolineSym(SymbolKind Kind,
+ TrampolineSym &Tramp) {
+ DictScope S(W, "Trampoline");
+ W.printEnum("Type", Tramp.Header.Type, getTrampolineNames());
+ W.printNumber("Size", Tramp.Header.Size);
+ W.printNumber("ThunkOff", Tramp.Header.ThunkOff);
+ W.printNumber("TargetOff", Tramp.Header.TargetOff);
+ W.printNumber("ThunkSection", Tramp.Header.ThunkSection);
+ W.printNumber("TargetSection", Tramp.Header.TargetSection);
+}
+
+void CVSymbolDumperImpl::visitSectionSym(SymbolKind Kind, SectionSym &Section) {
+ DictScope S(W, "Section");
+ W.printNumber("SectionNumber", Section.Header.SectionNumber);
+ W.printNumber("Alignment", Section.Header.Alignment);
+ W.printNumber("Reserved", Section.Header.Reserved);
+ W.printNumber("Rva", Section.Header.Rva);
+ W.printNumber("Length", Section.Header.Length);
+ W.printFlags("Characteristics", Section.Header.Characteristics,
+ getImageSectionCharacteristicNames(),
+ COFF::SectionCharacteristics(0x00F00000));
+
+ W.printString("Name", Section.Name);
+}
+
+void CVSymbolDumperImpl::visitCoffGroupSym(SymbolKind Kind,
+ CoffGroupSym &CoffGroup) {
+ DictScope S(W, "COFF Group");
+ W.printNumber("Size", CoffGroup.Header.Size);
+ W.printFlags("Characteristics", CoffGroup.Header.Characteristics,
+ getImageSectionCharacteristicNames(),
+ COFF::SectionCharacteristics(0x00F00000));
+ W.printNumber("Offset", CoffGroup.Header.Offset);
+ W.printNumber("Segment", CoffGroup.Header.Segment);
+ W.printString("Name", CoffGroup.Name);
+}
+
+void CVSymbolDumperImpl::visitBPRelativeSym(SymbolKind Kind,
+ BPRelativeSym &BPRel) {
+ DictScope S(W, "BPRelativeSym");
+
+ W.printNumber("Offset", BPRel.Header.Offset);
+ CVTD.printTypeIndex("Type", BPRel.Header.Type);
+ W.printString("VarName", BPRel.Name);
+}
+
+void CVSymbolDumperImpl::visitBuildInfoSym(SymbolKind Kind,
+ BuildInfoSym &BuildInfo) {
+ DictScope S(W, "BuildInfo");
+
+ W.printNumber("BuildId", BuildInfo.Header.BuildId);
+}
+
+void CVSymbolDumperImpl::visitCallSiteInfoSym(SymbolKind Kind,
+ CallSiteInfoSym &CallSiteInfo) {
+ DictScope S(W, "CallSiteInfo");
+
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField(
+ "CodeOffset", CallSiteInfo.getRelocationOffset(),
+ CallSiteInfo.Header.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", CallSiteInfo.Header.Segment);
+ W.printHex("Reserved", CallSiteInfo.Header.Reserved);
+ CVTD.printTypeIndex("Type", CallSiteInfo.Header.Type);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+}
+
+void CVSymbolDumperImpl::visitEnvBlockSym(SymbolKind Kind,
+ EnvBlockSym &EnvBlock) {
+ DictScope S(W, "EnvBlock");
+
+ W.printNumber("Reserved", EnvBlock.Header.Reserved);
+ ListScope L(W, "Entries");
+ for (auto Entry : EnvBlock.Fields) {
+ W.printString(Entry);
+ }
+}
+
+void CVSymbolDumperImpl::visitFileStaticSym(SymbolKind Kind,
+ FileStaticSym &FileStatic) {
+ DictScope S(W, "FileStatic");
+ W.printNumber("Index", FileStatic.Header.Index);
+ W.printNumber("ModFilenameOffset", FileStatic.Header.ModFilenameOffset);
+ W.printFlags("Flags", uint16_t(FileStatic.Header.Flags), getLocalFlagNames());
+ W.printString("Name", FileStatic.Name);
+}
+
+void CVSymbolDumperImpl::visitExportSym(SymbolKind Kind, ExportSym &Export) {
+ DictScope S(W, "Export");
+ W.printNumber("Ordinal", Export.Header.Ordinal);
+ W.printFlags("Flags", Export.Header.Flags, getExportSymFlagNames());
+ W.printString("Name", Export.Name);
+}
+
+void CVSymbolDumperImpl::visitCompile2Sym(SymbolKind Kind,
+ Compile2Sym &Compile2) {
+ DictScope S(W, "CompilerFlags2");
+
+ W.printEnum("Language", Compile2.Header.getLanguage(),
+ getSourceLanguageNames());
+ W.printFlags("Flags", Compile2.Header.flags & ~0xff,
+ getCompileSym2FlagNames());
+ W.printEnum("Machine", unsigned(Compile2.Header.Machine), getCPUTypeNames());
+ std::string FrontendVersion;
+ {
+ raw_string_ostream Out(FrontendVersion);
+ Out << Compile2.Header.VersionFrontendMajor << '.'
+ << Compile2.Header.VersionFrontendMinor << '.'
+ << Compile2.Header.VersionFrontendBuild;
+ }
+ std::string BackendVersion;
+ {
+ raw_string_ostream Out(BackendVersion);
+ Out << Compile2.Header.VersionBackendMajor << '.'
+ << Compile2.Header.VersionBackendMinor << '.'
+ << Compile2.Header.VersionBackendBuild;
+ }
+ W.printString("FrontendVersion", FrontendVersion);
+ W.printString("BackendVersion", BackendVersion);
+ W.printString("VersionName", Compile2.Version);
+}
+
+void CVSymbolDumperImpl::visitCompile3Sym(SymbolKind Kind,
+ Compile3Sym &Compile3) {
+ DictScope S(W, "CompilerFlags3");
+
+ W.printEnum("Language", Compile3.Header.getLanguage(),
+ getSourceLanguageNames());
+ W.printFlags("Flags", Compile3.Header.flags & ~0xff,
+ getCompileSym3FlagNames());
+ W.printEnum("Machine", unsigned(Compile3.Header.Machine), getCPUTypeNames());
+ std::string FrontendVersion;
+ {
+ raw_string_ostream Out(FrontendVersion);
+ Out << Compile3.Header.VersionFrontendMajor << '.'
+ << Compile3.Header.VersionFrontendMinor << '.'
+ << Compile3.Header.VersionFrontendBuild << '.'
+ << Compile3.Header.VersionFrontendQFE;
+ }
+ std::string BackendVersion;
+ {
+ raw_string_ostream Out(BackendVersion);
+ Out << Compile3.Header.VersionBackendMajor << '.'
+ << Compile3.Header.VersionBackendMinor << '.'
+ << Compile3.Header.VersionBackendBuild << '.'
+ << Compile3.Header.VersionBackendQFE;
+ }
+ W.printString("FrontendVersion", FrontendVersion);
+ W.printString("BackendVersion", BackendVersion);
+ W.printString("VersionName", Compile3.Version);
+}
+
+void CVSymbolDumperImpl::visitConstantSym(SymbolKind Kind,
+ ConstantSym &Constant) {
+ DictScope S(W, "Constant");
+
+ CVTD.printTypeIndex("Type", Constant.Header.Type);
+ W.printNumber("Value", Constant.Value);
+ W.printString("Name", Constant.Name);
+}
+
+void CVSymbolDumperImpl::visitDataSym(SymbolKind Kind, DataSym &Data) {
+ DictScope S(W, "DataSym");
+
+ W.printEnum("Kind", uint16_t(Kind), getSymbolTypeNames());
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(),
+ Data.Header.DataOffset, &LinkageName);
+ }
+ CVTD.printTypeIndex("Type", Data.Header.Type);
+ W.printString("DisplayName", Data.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+}
+
+void CVSymbolDumperImpl::visitDefRangeFramePointerRelFullScopeSym(
+ SymbolKind Kind,
+ DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) {
+ DictScope S(W, "DefRangeFramePointerRelFullScope");
+ W.printNumber("Offset", DefRangeFramePointerRelFullScope.Header.Offset);
+}
+
+void CVSymbolDumperImpl::visitDefRangeFramePointerRelSym(
+ SymbolKind Kind, DefRangeFramePointerRelSym &DefRangeFramePointerRel) {
+ DictScope S(W, "DefRangeFramePointerRel");
+
+ W.printNumber("Offset", DefRangeFramePointerRel.Header.Offset);
+ printLocalVariableAddrRange(DefRangeFramePointerRel.Header.Range,
+ DefRangeFramePointerRel.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeFramePointerRel.Gaps);
+}
+
+void CVSymbolDumperImpl::visitDefRangeRegisterRelSym(
+ SymbolKind Kind, DefRangeRegisterRelSym &DefRangeRegisterRel) {
+ DictScope S(W, "DefRangeRegisterRel");
+
+ W.printNumber("BaseRegister", DefRangeRegisterRel.Header.BaseRegister);
+ W.printBoolean("HasSpilledUDTMember",
+ DefRangeRegisterRel.hasSpilledUDTMember());
+ W.printNumber("OffsetInParent", DefRangeRegisterRel.offsetInParent());
+ W.printNumber("BasePointerOffset",
+ DefRangeRegisterRel.Header.BasePointerOffset);
+ printLocalVariableAddrRange(DefRangeRegisterRel.Header.Range,
+ DefRangeRegisterRel.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeRegisterRel.Gaps);
+}
+
+void CVSymbolDumperImpl::visitDefRangeRegisterSym(
+ SymbolKind Kind, DefRangeRegisterSym &DefRangeRegister) {
+ DictScope S(W, "DefRangeRegister");
+
+ W.printNumber("Register", DefRangeRegister.Header.Register);
+ W.printNumber("MayHaveNoName", DefRangeRegister.Header.MayHaveNoName);
+ printLocalVariableAddrRange(DefRangeRegister.Header.Range,
+ DefRangeRegister.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeRegister.Gaps);
+}
+
+void CVSymbolDumperImpl::visitDefRangeSubfieldRegisterSym(
+ SymbolKind Kind, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) {
+ DictScope S(W, "DefRangeSubfieldRegister");
+
+ W.printNumber("Register", DefRangeSubfieldRegister.Header.Register);
+ W.printNumber("MayHaveNoName", DefRangeSubfieldRegister.Header.MayHaveNoName);
+ W.printNumber("OffsetInParent",
+ DefRangeSubfieldRegister.Header.OffsetInParent);
+ printLocalVariableAddrRange(DefRangeSubfieldRegister.Header.Range,
+ DefRangeSubfieldRegister.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeSubfieldRegister.Gaps);
+}
+
+void CVSymbolDumperImpl::visitDefRangeSubfieldSym(
+ SymbolKind Kind, DefRangeSubfieldSym &DefRangeSubfield) {
+ DictScope S(W, "DefRangeSubfield");
+
+ if (ObjDelegate) {
+ StringRef StringTable = ObjDelegate->getStringTable();
+ auto ProgramStringTableOffset = DefRangeSubfield.Header.Program;
+ if (ProgramStringTableOffset >= StringTable.size())
+ return parseError();
+ StringRef Program =
+ StringTable.drop_front(ProgramStringTableOffset).split('\0').first;
+ W.printString("Program", Program);
+ }
+ W.printNumber("OffsetInParent", DefRangeSubfield.Header.OffsetInParent);
+ printLocalVariableAddrRange(DefRangeSubfield.Header.Range,
+ DefRangeSubfield.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeSubfield.Gaps);
+}
+
+void CVSymbolDumperImpl::visitDefRangeSym(SymbolKind Kind,
+ DefRangeSym &DefRange) {
+ DictScope S(W, "DefRange");
+
+ if (ObjDelegate) {
+ StringRef StringTable = ObjDelegate->getStringTable();
+ auto ProgramStringTableOffset = DefRange.Header.Program;
+ if (ProgramStringTableOffset >= StringTable.size())
+ return parseError();
+ StringRef Program =
+ StringTable.drop_front(ProgramStringTableOffset).split('\0').first;
+ W.printString("Program", Program);
+ }
+ printLocalVariableAddrRange(DefRange.Header.Range,
+ DefRange.getRelocationOffset());
+ printLocalVariableAddrGap(DefRange.Gaps);
+}
+
+void CVSymbolDumperImpl::visitFrameCookieSym(SymbolKind Kind,
+ FrameCookieSym &FrameCookie) {
+ DictScope S(W, "FrameCookie");
+
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField(
+ "CodeOffset", FrameCookie.getRelocationOffset(),
+ FrameCookie.Header.CodeOffset, &LinkageName);
+ }
+ W.printHex("Register", FrameCookie.Header.Register);
+ W.printEnum("CookieKind", uint16_t(FrameCookie.Header.CookieKind),
+ getFrameCookieKindNames());
+ W.printHex("Flags", FrameCookie.Header.Flags);
+}
+
+void CVSymbolDumperImpl::visitFrameProcSym(SymbolKind Kind,
+ FrameProcSym &FrameProc) {
+ DictScope S(W, "FrameProc");
+
+ W.printHex("TotalFrameBytes", FrameProc.Header.TotalFrameBytes);
+ W.printHex("PaddingFrameBytes", FrameProc.Header.PaddingFrameBytes);
+ W.printHex("OffsetToPadding", FrameProc.Header.OffsetToPadding);
+ W.printHex("BytesOfCalleeSavedRegisters",
+ FrameProc.Header.BytesOfCalleeSavedRegisters);
+ W.printHex("OffsetOfExceptionHandler",
+ FrameProc.Header.OffsetOfExceptionHandler);
+ W.printHex("SectionIdOfExceptionHandler",
+ FrameProc.Header.SectionIdOfExceptionHandler);
+ W.printFlags("Flags", FrameProc.Header.Flags, getFrameProcSymFlagNames());
+}
+
+void CVSymbolDumperImpl::visitHeapAllocationSiteSym(
+ SymbolKind Kind, HeapAllocationSiteSym &HeapAllocSite) {
+ DictScope S(W, "HeapAllocationSite");
+
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField(
+ "CodeOffset", HeapAllocSite.getRelocationOffset(),
+ HeapAllocSite.Header.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", HeapAllocSite.Header.Segment);
+ W.printHex("CallInstructionSize", HeapAllocSite.Header.CallInstructionSize);
+ CVTD.printTypeIndex("Type", HeapAllocSite.Header.Type);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+}
+
+void CVSymbolDumperImpl::visitInlineSiteSym(SymbolKind Kind,
+ InlineSiteSym &InlineSite) {
+ DictScope S(W, "InlineSite");
+
+ W.printHex("PtrParent", InlineSite.Header.PtrParent);
+ W.printHex("PtrEnd", InlineSite.Header.PtrEnd);
+ CVTD.printTypeIndex("Inlinee", InlineSite.Header.Inlinee);
+
+ ListScope BinaryAnnotations(W, "BinaryAnnotations");
+ for (auto &Annotation : InlineSite.annotations()) {
+ switch (Annotation.OpCode) {
+ case BinaryAnnotationsOpCode::Invalid:
+ return parseError();
+ case BinaryAnnotationsOpCode::CodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeLength:
+ W.printHex(Annotation.Name, Annotation.U1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
+ case BinaryAnnotationsOpCode::ChangeLineEndDelta:
+ case BinaryAnnotationsOpCode::ChangeRangeKind:
+ case BinaryAnnotationsOpCode::ChangeColumnStart:
+ case BinaryAnnotationsOpCode::ChangeColumnEnd:
+ W.printNumber(Annotation.Name, Annotation.U1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeLineOffset:
+ case BinaryAnnotationsOpCode::ChangeColumnEndDelta:
+ W.printNumber(Annotation.Name, Annotation.S1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeFile:
+ if (ObjDelegate) {
+ W.printHex("ChangeFile",
+ ObjDelegate->getFileNameForFileOffset(Annotation.U1),
+ Annotation.U1);
+ } else {
+ W.printHex("ChangeFile", Annotation.U1);
+ }
+
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: {
+ W.startLine() << "ChangeCodeOffsetAndLineOffset: {CodeOffset: "
+ << W.hex(Annotation.U1) << ", LineOffset: " << Annotation.S1
+ << "}\n";
+ break;
+ }
+ case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: {
+ W.startLine() << "ChangeCodeLengthAndCodeOffset: {CodeOffset: "
+ << W.hex(Annotation.U2)
+ << ", Length: " << W.hex(Annotation.U1) << "}\n";
+ break;
+ }
+ }
+ }
+}
+
+void CVSymbolDumperImpl::visitRegisterSym(SymbolKind Kind,
+ RegisterSym &Register) {
+ DictScope S(W, "RegisterSym");
+ W.printNumber("Type", Register.Header.Index);
+ W.printEnum("Seg", uint16_t(Register.Header.Register), getRegisterNames());
+ W.printString("Name", Register.Name);
+}
+
+void CVSymbolDumperImpl::visitPublicSym32(SymbolKind Kind,
+ PublicSym32 &Public) {
+ DictScope S(W, "PublicSym");
+ W.printNumber("Type", Public.Header.Index);
+ W.printNumber("Seg", Public.Header.Seg);
+ W.printNumber("Off", Public.Header.Off);
+ W.printString("Name", Public.Name);
+}
+
+void CVSymbolDumperImpl::visitProcRefSym(SymbolKind Kind, ProcRefSym &ProcRef) {
+ DictScope S(W, "ProcRef");
+ W.printNumber("SumName", ProcRef.Header.SumName);
+ W.printNumber("SymOffset", ProcRef.Header.SymOffset);
+ W.printNumber("Mod", ProcRef.Header.Mod);
+ W.printString("Name", ProcRef.Name);
+}
+
+void CVSymbolDumperImpl::visitLabelSym(SymbolKind Kind, LabelSym &Label) {
+ DictScope S(W, "Label");
+
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset", Label.getRelocationOffset(),
+ Label.Header.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", Label.Header.Segment);
+ W.printHex("Flags", Label.Header.Flags);
+ W.printFlags("Flags", Label.Header.Flags, getProcSymFlagNames());
+ W.printString("DisplayName", Label.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+}
+
+void CVSymbolDumperImpl::visitLocalSym(SymbolKind Kind, LocalSym &Local) {
+ DictScope S(W, "Local");
+
+ CVTD.printTypeIndex("Type", Local.Header.Type);
+ W.printFlags("Flags", uint16_t(Local.Header.Flags), getLocalFlagNames());
+ W.printString("VarName", Local.Name);
+}
+
+void CVSymbolDumperImpl::visitObjNameSym(SymbolKind Kind, ObjNameSym &ObjName) {
+ DictScope S(W, "ObjectName");
+
+ W.printHex("Signature", ObjName.Header.Signature);
+ W.printString("ObjectName", ObjName.Name);
+}
+
+void CVSymbolDumperImpl::visitProcSym(SymbolKind Kind, ProcSym &Proc) {
+ DictScope S(W, "ProcStart");
+
+ if (InFunctionScope)
+ return parseError();
+
+ InFunctionScope = true;
+
+ StringRef LinkageName;
+ W.printEnum("Kind", uint16_t(Kind), getSymbolTypeNames());
+ W.printHex("PtrParent", Proc.Header.PtrParent);
+ W.printHex("PtrEnd", Proc.Header.PtrEnd);
+ W.printHex("PtrNext", Proc.Header.PtrNext);
+ W.printHex("CodeSize", Proc.Header.CodeSize);
+ W.printHex("DbgStart", Proc.Header.DbgStart);
+ W.printHex("DbgEnd", Proc.Header.DbgEnd);
+ CVTD.printTypeIndex("FunctionType", Proc.Header.FunctionType);
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset", Proc.getRelocationOffset(),
+ Proc.Header.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", Proc.Header.Segment);
+ W.printFlags("Flags", static_cast<uint8_t>(Proc.Header.Flags),
+ getProcSymFlagNames());
+ W.printString("DisplayName", Proc.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+}
+
+void CVSymbolDumperImpl::visitScopeEndSym(SymbolKind Kind,
+ ScopeEndSym &ScopeEnd) {
+ if (Kind == SymbolKind::S_END)
+ DictScope S(W, "BlockEnd");
+ else if (Kind == SymbolKind::S_PROC_ID_END)
+ DictScope S(W, "ProcEnd");
+ else if (Kind == SymbolKind::S_INLINESITE_END)
+ DictScope S(W, "InlineSiteEnd");
+
+ InFunctionScope = false;
+}
+
+void CVSymbolDumperImpl::visitCallerSym(SymbolKind Kind, CallerSym &Caller) {
+ ListScope S(W, Kind == S_CALLEES ? "Callees" : "Callers");
+ for (auto FuncID : Caller.Indices)
+ CVTD.printTypeIndex("FuncID", FuncID);
+}
+
+void CVSymbolDumperImpl::visitRegRelativeSym(SymbolKind Kind,
+ RegRelativeSym &RegRel) {
+ DictScope S(W, "RegRelativeSym");
+
+ W.printHex("Offset", RegRel.Header.Offset);
+ CVTD.printTypeIndex("Type", RegRel.Header.Type);
+ W.printHex("Register", RegRel.Header.Register);
+ W.printString("VarName", RegRel.Name);
+}
+
+void CVSymbolDumperImpl::visitThreadLocalDataSym(SymbolKind Kind,
+ ThreadLocalDataSym &Data) {
+ DictScope S(W, "ThreadLocalDataSym");
+
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(),
+ Data.Header.DataOffset, &LinkageName);
+ }
+ CVTD.printTypeIndex("Type", Data.Header.Type);
+ W.printString("DisplayName", Data.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+}
+
+void CVSymbolDumperImpl::visitUDTSym(SymbolKind Kind, UDTSym &UDT) {
+ DictScope S(W, "UDT");
+ CVTD.printTypeIndex("Type", UDT.Header.Type);
+ W.printString("UDTName", UDT.Name);
+}
+
+void CVSymbolDumperImpl::visitUnknownSymbol(SymbolKind Kind,
+ ArrayRef<uint8_t> Data) {
+ DictScope S(W, "UnknownSym");
+ W.printEnum("Kind", uint16_t(Kind), getSymbolTypeNames());
+ W.printNumber("Length", uint32_t(Data.size()));
+}
+
+bool CVSymbolDumper::dump(const CVRecord<SymbolKind> &Record) {
+ CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes);
+ Dumper.visitSymbolRecord(Record);
+ return !Dumper.hadError();
+}
+
+bool CVSymbolDumper::dump(const CVSymbolArray &Symbols) {
+ CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes);
+ Dumper.visitSymbolStream(Symbols);
+ return !Dumper.hadError();
+}
diff --git a/lib/DebugInfo/CodeView/TypeDumper.cpp b/lib/DebugInfo/CodeView/TypeDumper.cpp
new file mode 100644
index 000000000000..345e2a49888c
--- /dev/null
+++ b/lib/DebugInfo/CodeView/TypeDumper.cpp
@@ -0,0 +1,696 @@
+//===-- TypeDumper.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeDumper.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/ByteStream.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+/// The names here all end in "*". If the simple type is a pointer type, we
+/// return the whole name. Otherwise we lop off the last character in our
+/// StringRef.
+static const EnumEntry<SimpleTypeKind> SimpleTypeNames[] = {
+ {"void*", SimpleTypeKind::Void},
+ {"<not translated>*", SimpleTypeKind::NotTranslated},
+ {"HRESULT*", SimpleTypeKind::HResult},
+ {"signed char*", SimpleTypeKind::SignedCharacter},
+ {"unsigned char*", SimpleTypeKind::UnsignedCharacter},
+ {"char*", SimpleTypeKind::NarrowCharacter},
+ {"wchar_t*", SimpleTypeKind::WideCharacter},
+ {"char16_t*", SimpleTypeKind::Character16},
+ {"char32_t*", SimpleTypeKind::Character32},
+ {"__int8*", SimpleTypeKind::SByte},
+ {"unsigned __int8*", SimpleTypeKind::Byte},
+ {"short*", SimpleTypeKind::Int16Short},
+ {"unsigned short*", SimpleTypeKind::UInt16Short},
+ {"__int16*", SimpleTypeKind::Int16},
+ {"unsigned __int16*", SimpleTypeKind::UInt16},
+ {"long*", SimpleTypeKind::Int32Long},
+ {"unsigned long*", SimpleTypeKind::UInt32Long},
+ {"int*", SimpleTypeKind::Int32},
+ {"unsigned*", SimpleTypeKind::UInt32},
+ {"__int64*", SimpleTypeKind::Int64Quad},
+ {"unsigned __int64*", SimpleTypeKind::UInt64Quad},
+ {"__int64*", SimpleTypeKind::Int64},
+ {"unsigned __int64*", SimpleTypeKind::UInt64},
+ {"__int128*", SimpleTypeKind::Int128},
+ {"unsigned __int128*", SimpleTypeKind::UInt128},
+ {"__half*", SimpleTypeKind::Float16},
+ {"float*", SimpleTypeKind::Float32},
+ {"float*", SimpleTypeKind::Float32PartialPrecision},
+ {"__float48*", SimpleTypeKind::Float48},
+ {"double*", SimpleTypeKind::Float64},
+ {"long double*", SimpleTypeKind::Float80},
+ {"__float128*", SimpleTypeKind::Float128},
+ {"_Complex float*", SimpleTypeKind::Complex32},
+ {"_Complex double*", SimpleTypeKind::Complex64},
+ {"_Complex long double*", SimpleTypeKind::Complex80},
+ {"_Complex __float128*", SimpleTypeKind::Complex128},
+ {"bool*", SimpleTypeKind::Boolean8},
+ {"__bool16*", SimpleTypeKind::Boolean16},
+ {"__bool32*", SimpleTypeKind::Boolean32},
+ {"__bool64*", SimpleTypeKind::Boolean64},
+};
+
+static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
+#define CV_TYPE(enum, val) {#enum, enum},
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+};
+
+#define ENUM_ENTRY(enum_class, enum) \
+ { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
+
+static const EnumEntry<uint16_t> ClassOptionNames[] = {
+ ENUM_ENTRY(ClassOptions, Packed),
+ ENUM_ENTRY(ClassOptions, HasConstructorOrDestructor),
+ ENUM_ENTRY(ClassOptions, HasOverloadedOperator),
+ ENUM_ENTRY(ClassOptions, Nested),
+ ENUM_ENTRY(ClassOptions, ContainsNestedClass),
+ ENUM_ENTRY(ClassOptions, HasOverloadedAssignmentOperator),
+ ENUM_ENTRY(ClassOptions, HasConversionOperator),
+ ENUM_ENTRY(ClassOptions, ForwardReference),
+ ENUM_ENTRY(ClassOptions, Scoped),
+ ENUM_ENTRY(ClassOptions, HasUniqueName),
+ ENUM_ENTRY(ClassOptions, Sealed),
+ ENUM_ENTRY(ClassOptions, Intrinsic),
+};
+
+static const EnumEntry<uint8_t> MemberAccessNames[] = {
+ ENUM_ENTRY(MemberAccess, None),
+ ENUM_ENTRY(MemberAccess, Private),
+ ENUM_ENTRY(MemberAccess, Protected),
+ ENUM_ENTRY(MemberAccess, Public),
+};
+
+static const EnumEntry<uint16_t> MethodOptionNames[] = {
+ ENUM_ENTRY(MethodOptions, Pseudo),
+ ENUM_ENTRY(MethodOptions, NoInherit),
+ ENUM_ENTRY(MethodOptions, NoConstruct),
+ ENUM_ENTRY(MethodOptions, CompilerGenerated),
+ ENUM_ENTRY(MethodOptions, Sealed),
+};
+
+static const EnumEntry<uint16_t> MemberKindNames[] = {
+ ENUM_ENTRY(MethodKind, Vanilla),
+ ENUM_ENTRY(MethodKind, Virtual),
+ ENUM_ENTRY(MethodKind, Static),
+ ENUM_ENTRY(MethodKind, Friend),
+ ENUM_ENTRY(MethodKind, IntroducingVirtual),
+ ENUM_ENTRY(MethodKind, PureVirtual),
+ ENUM_ENTRY(MethodKind, PureIntroducingVirtual),
+};
+
+static const EnumEntry<uint8_t> PtrKindNames[] = {
+ ENUM_ENTRY(PointerKind, Near16),
+ ENUM_ENTRY(PointerKind, Far16),
+ ENUM_ENTRY(PointerKind, Huge16),
+ ENUM_ENTRY(PointerKind, BasedOnSegment),
+ ENUM_ENTRY(PointerKind, BasedOnValue),
+ ENUM_ENTRY(PointerKind, BasedOnSegmentValue),
+ ENUM_ENTRY(PointerKind, BasedOnAddress),
+ ENUM_ENTRY(PointerKind, BasedOnSegmentAddress),
+ ENUM_ENTRY(PointerKind, BasedOnType),
+ ENUM_ENTRY(PointerKind, BasedOnSelf),
+ ENUM_ENTRY(PointerKind, Near32),
+ ENUM_ENTRY(PointerKind, Far32),
+ ENUM_ENTRY(PointerKind, Near64),
+};
+
+static const EnumEntry<uint8_t> PtrModeNames[] = {
+ ENUM_ENTRY(PointerMode, Pointer),
+ ENUM_ENTRY(PointerMode, LValueReference),
+ ENUM_ENTRY(PointerMode, PointerToDataMember),
+ ENUM_ENTRY(PointerMode, PointerToMemberFunction),
+ ENUM_ENTRY(PointerMode, RValueReference),
+};
+
+static const EnumEntry<uint16_t> PtrMemberRepNames[] = {
+ ENUM_ENTRY(PointerToMemberRepresentation, Unknown),
+ ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceData),
+ ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceData),
+ ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceData),
+ ENUM_ENTRY(PointerToMemberRepresentation, GeneralData),
+ ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceFunction),
+ ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceFunction),
+ ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceFunction),
+ ENUM_ENTRY(PointerToMemberRepresentation, GeneralFunction),
+};
+
+static const EnumEntry<uint16_t> TypeModifierNames[] = {
+ ENUM_ENTRY(ModifierOptions, Const),
+ ENUM_ENTRY(ModifierOptions, Volatile),
+ ENUM_ENTRY(ModifierOptions, Unaligned),
+};
+
+static const EnumEntry<uint8_t> CallingConventions[] = {
+ ENUM_ENTRY(CallingConvention, NearC),
+ ENUM_ENTRY(CallingConvention, FarC),
+ ENUM_ENTRY(CallingConvention, NearPascal),
+ ENUM_ENTRY(CallingConvention, FarPascal),
+ ENUM_ENTRY(CallingConvention, NearFast),
+ ENUM_ENTRY(CallingConvention, FarFast),
+ ENUM_ENTRY(CallingConvention, NearStdCall),
+ ENUM_ENTRY(CallingConvention, FarStdCall),
+ ENUM_ENTRY(CallingConvention, NearSysCall),
+ ENUM_ENTRY(CallingConvention, FarSysCall),
+ ENUM_ENTRY(CallingConvention, ThisCall),
+ ENUM_ENTRY(CallingConvention, MipsCall),
+ ENUM_ENTRY(CallingConvention, Generic),
+ ENUM_ENTRY(CallingConvention, AlphaCall),
+ ENUM_ENTRY(CallingConvention, PpcCall),
+ ENUM_ENTRY(CallingConvention, SHCall),
+ ENUM_ENTRY(CallingConvention, ArmCall),
+ ENUM_ENTRY(CallingConvention, AM33Call),
+ ENUM_ENTRY(CallingConvention, TriCall),
+ ENUM_ENTRY(CallingConvention, SH5Call),
+ ENUM_ENTRY(CallingConvention, M32RCall),
+ ENUM_ENTRY(CallingConvention, ClrCall),
+ ENUM_ENTRY(CallingConvention, Inline),
+ ENUM_ENTRY(CallingConvention, NearVector),
+};
+
+static const EnumEntry<uint8_t> FunctionOptionEnum[] = {
+ ENUM_ENTRY(FunctionOptions, CxxReturnUdt),
+ ENUM_ENTRY(FunctionOptions, Constructor),
+ ENUM_ENTRY(FunctionOptions, ConstructorWithVirtualBases),
+};
+
+#undef ENUM_ENTRY
+
+static StringRef getLeafTypeName(TypeLeafKind LT) {
+ switch (LT) {
+#define TYPE_RECORD(ename, value, name) \
+ case ename: \
+ return #name;
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+ case LF_FIELDLIST:
+ return "FieldList";
+ default:
+ break;
+ }
+ return "UnknownLeaf";
+}
+
+Error CVTypeDumper::visitTypeBegin(const CVRecord<TypeLeafKind> &Record) {
+ // Reset Name to the empty string. If the visitor sets it, we know it.
+ Name = "";
+
+ W->startLine() << getLeafTypeName(Record.Type) << " ("
+ << HexNumber(getNextTypeIndex()) << ") {\n";
+ W->indent();
+ W->printEnum("TypeLeafKind", unsigned(Record.Type),
+ makeArrayRef(LeafTypeNames));
+ return Error::success();
+}
+
+Error CVTypeDumper::visitTypeEnd(const CVRecord<TypeLeafKind> &Record) {
+ if (Record.Type == LF_FIELDLIST)
+ Name = "<field list>";
+
+ // Always record some name for every type, even if Name is empty. CVUDTNames
+ // is indexed by type index, and must have one entry for every type.
+ recordType(Name);
+
+ if (PrintRecordBytes)
+ W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data));
+
+ W->unindent();
+ W->startLine() << "}\n";
+ return Error::success();
+}
+
+Error CVTypeDumper::visitStringId(StringIdRecord &String) {
+ printTypeIndex("Id", String.getId());
+ W->printString("StringData", String.getString());
+ // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE.
+ Name = String.getString();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitArgList(ArgListRecord &Args) {
+ auto Indices = Args.getIndices();
+ uint32_t Size = Indices.size();
+ W->printNumber("NumArgs", Size);
+ ListScope Arguments(*W, "Arguments");
+ SmallString<256> TypeName("(");
+ for (uint32_t I = 0; I < Size; ++I) {
+ printTypeIndex("ArgType", Indices[I]);
+ StringRef ArgTypeName = getTypeName(Indices[I]);
+ TypeName.append(ArgTypeName);
+ if (I + 1 != Size)
+ TypeName.append(", ");
+ }
+ TypeName.push_back(')');
+ Name = saveName(TypeName);
+ return Error::success();
+}
+
+Error CVTypeDumper::visitClass(ClassRecord &Class) {
+ uint16_t Props = static_cast<uint16_t>(Class.getOptions());
+ W->printNumber("MemberCount", Class.getMemberCount());
+ W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
+ printTypeIndex("FieldList", Class.getFieldList());
+ printTypeIndex("DerivedFrom", Class.getDerivationList());
+ printTypeIndex("VShape", Class.getVTableShape());
+ W->printNumber("SizeOf", Class.getSize());
+ W->printString("Name", Class.getName());
+ if (Props & uint16_t(ClassOptions::HasUniqueName))
+ W->printString("LinkageName", Class.getUniqueName());
+ Name = Class.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitUnion(UnionRecord &Union) {
+ uint16_t Props = static_cast<uint16_t>(Union.getOptions());
+ W->printNumber("MemberCount", Union.getMemberCount());
+ W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
+ printTypeIndex("FieldList", Union.getFieldList());
+ W->printNumber("SizeOf", Union.getSize());
+ W->printString("Name", Union.getName());
+ if (Props & uint16_t(ClassOptions::HasUniqueName))
+ W->printString("LinkageName", Union.getUniqueName());
+ Name = Union.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitEnum(EnumRecord &Enum) {
+ uint16_t Props = static_cast<uint16_t>(Enum.getOptions());
+ W->printNumber("NumEnumerators", Enum.getMemberCount());
+ W->printFlags("Properties", uint16_t(Enum.getOptions()),
+ makeArrayRef(ClassOptionNames));
+ printTypeIndex("UnderlyingType", Enum.getUnderlyingType());
+ printTypeIndex("FieldListType", Enum.getFieldList());
+ W->printString("Name", Enum.getName());
+ if (Props & uint16_t(ClassOptions::HasUniqueName))
+ W->printString("LinkageName", Enum.getUniqueName());
+ Name = Enum.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitArray(ArrayRecord &AT) {
+ printTypeIndex("ElementType", AT.getElementType());
+ printTypeIndex("IndexType", AT.getIndexType());
+ W->printNumber("SizeOf", AT.getSize());
+ W->printString("Name", AT.getName());
+ Name = AT.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitVFTable(VFTableRecord &VFT) {
+ printTypeIndex("CompleteClass", VFT.getCompleteClass());
+ printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable());
+ W->printHex("VFPtrOffset", VFT.getVFPtrOffset());
+ W->printString("VFTableName", VFT.getName());
+ for (auto N : VFT.getMethodNames())
+ W->printString("MethodName", N);
+ Name = VFT.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitMemberFuncId(MemberFuncIdRecord &Id) {
+ printTypeIndex("ClassType", Id.getClassType());
+ printTypeIndex("FunctionType", Id.getFunctionType());
+ W->printString("Name", Id.getName());
+ Name = Id.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitProcedure(ProcedureRecord &Proc) {
+ printTypeIndex("ReturnType", Proc.getReturnType());
+ W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()),
+ makeArrayRef(CallingConventions));
+ W->printFlags("FunctionOptions", uint8_t(Proc.getOptions()),
+ makeArrayRef(FunctionOptionEnum));
+ W->printNumber("NumParameters", Proc.getParameterCount());
+ printTypeIndex("ArgListType", Proc.getArgumentList());
+
+ StringRef ReturnTypeName = getTypeName(Proc.getReturnType());
+ StringRef ArgListTypeName = getTypeName(Proc.getArgumentList());
+ SmallString<256> TypeName(ReturnTypeName);
+ TypeName.push_back(' ');
+ TypeName.append(ArgListTypeName);
+ Name = saveName(TypeName);
+ return Error::success();
+}
+
+Error CVTypeDumper::visitMemberFunction(MemberFunctionRecord &MF) {
+ printTypeIndex("ReturnType", MF.getReturnType());
+ printTypeIndex("ClassType", MF.getClassType());
+ printTypeIndex("ThisType", MF.getThisType());
+ W->printEnum("CallingConvention", uint8_t(MF.getCallConv()),
+ makeArrayRef(CallingConventions));
+ W->printFlags("FunctionOptions", uint8_t(MF.getOptions()),
+ makeArrayRef(FunctionOptionEnum));
+ W->printNumber("NumParameters", MF.getParameterCount());
+ printTypeIndex("ArgListType", MF.getArgumentList());
+ W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment());
+
+ StringRef ReturnTypeName = getTypeName(MF.getReturnType());
+ StringRef ClassTypeName = getTypeName(MF.getClassType());
+ StringRef ArgListTypeName = getTypeName(MF.getArgumentList());
+ SmallString<256> TypeName(ReturnTypeName);
+ TypeName.push_back(' ');
+ TypeName.append(ClassTypeName);
+ TypeName.append("::");
+ TypeName.append(ArgListTypeName);
+ Name = saveName(TypeName);
+ return Error::success();
+}
+
+Error CVTypeDumper::visitMethodOverloadList(
+ MethodOverloadListRecord &MethodList) {
+ for (auto &M : MethodList.getMethods()) {
+ ListScope S(*W, "Method");
+ printMemberAttributes(M.getAccess(), M.getKind(), M.getOptions());
+ printTypeIndex("Type", M.getType());
+ if (M.isIntroducingVirtual())
+ W->printHex("VFTableOffset", M.getVFTableOffset());
+ }
+ return Error::success();
+}
+
+Error CVTypeDumper::visitFuncId(FuncIdRecord &Func) {
+ printTypeIndex("ParentScope", Func.getParentScope());
+ printTypeIndex("FunctionType", Func.getFunctionType());
+ W->printString("Name", Func.getName());
+ Name = Func.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitTypeServer2(TypeServer2Record &TS) {
+ W->printBinary("Signature", TS.getGuid());
+ W->printNumber("Age", TS.getAge());
+ W->printString("Name", TS.getName());
+ Name = TS.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitPointer(PointerRecord &Ptr) {
+ printTypeIndex("PointeeType", Ptr.getReferentType());
+ W->printHex("PointerAttributes", uint32_t(Ptr.getOptions()));
+ W->printEnum("PtrType", unsigned(Ptr.getPointerKind()),
+ makeArrayRef(PtrKindNames));
+ W->printEnum("PtrMode", unsigned(Ptr.getMode()), makeArrayRef(PtrModeNames));
+
+ W->printNumber("IsFlat", Ptr.isFlat());
+ W->printNumber("IsConst", Ptr.isConst());
+ W->printNumber("IsVolatile", Ptr.isVolatile());
+ W->printNumber("IsUnaligned", Ptr.isUnaligned());
+ W->printNumber("SizeOf", Ptr.getSize());
+
+ if (Ptr.isPointerToMember()) {
+ const MemberPointerInfo &MI = Ptr.getMemberInfo();
+
+ printTypeIndex("ClassType", MI.getContainingType());
+ W->printEnum("Representation", uint16_t(MI.getRepresentation()),
+ makeArrayRef(PtrMemberRepNames));
+
+ StringRef PointeeName = getTypeName(Ptr.getReferentType());
+ StringRef ClassName = getTypeName(MI.getContainingType());
+ SmallString<256> TypeName(PointeeName);
+ TypeName.push_back(' ');
+ TypeName.append(ClassName);
+ TypeName.append("::*");
+ Name = saveName(TypeName);
+ } else {
+ SmallString<256> TypeName;
+ if (Ptr.isConst())
+ TypeName.append("const ");
+ if (Ptr.isVolatile())
+ TypeName.append("volatile ");
+ if (Ptr.isUnaligned())
+ TypeName.append("__unaligned ");
+
+ TypeName.append(getTypeName(Ptr.getReferentType()));
+
+ if (Ptr.getMode() == PointerMode::LValueReference)
+ TypeName.append("&");
+ else if (Ptr.getMode() == PointerMode::RValueReference)
+ TypeName.append("&&");
+ else if (Ptr.getMode() == PointerMode::Pointer)
+ TypeName.append("*");
+
+ if (!TypeName.empty())
+ Name = saveName(TypeName);
+ }
+ return Error::success();
+}
+
+Error CVTypeDumper::visitModifier(ModifierRecord &Mod) {
+ uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
+ printTypeIndex("ModifiedType", Mod.getModifiedType());
+ W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames));
+
+ StringRef ModifiedName = getTypeName(Mod.getModifiedType());
+ SmallString<256> TypeName;
+ if (Mods & uint16_t(ModifierOptions::Const))
+ TypeName.append("const ");
+ if (Mods & uint16_t(ModifierOptions::Volatile))
+ TypeName.append("volatile ");
+ if (Mods & uint16_t(ModifierOptions::Unaligned))
+ TypeName.append("__unaligned ");
+ TypeName.append(ModifiedName);
+ Name = saveName(TypeName);
+ return Error::success();
+}
+
+Error CVTypeDumper::visitBitField(BitFieldRecord &BitField) {
+ printTypeIndex("Type", BitField.getType());
+ W->printNumber("BitSize", BitField.getBitSize());
+ W->printNumber("BitOffset", BitField.getBitOffset());
+ return Error::success();
+}
+
+Error CVTypeDumper::visitVFTableShape(VFTableShapeRecord &Shape) {
+ W->printNumber("VFEntryCount", Shape.getEntryCount());
+ return Error::success();
+}
+
+Error CVTypeDumper::visitUdtSourceLine(UdtSourceLineRecord &Line) {
+ printTypeIndex("UDT", Line.getUDT());
+ printTypeIndex("SourceFile", Line.getSourceFile());
+ W->printNumber("LineNumber", Line.getLineNumber());
+ return Error::success();
+}
+
+Error CVTypeDumper::visitUdtModSourceLine(UdtModSourceLineRecord &Line) {
+ printTypeIndex("UDT", Line.getUDT());
+ printTypeIndex("SourceFile", Line.getSourceFile());
+ W->printNumber("LineNumber", Line.getLineNumber());
+ W->printNumber("Module", Line.getModule());
+ return Error::success();
+}
+
+Error CVTypeDumper::visitBuildInfo(BuildInfoRecord &Args) {
+ W->printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size()));
+
+ ListScope Arguments(*W, "Arguments");
+ for (auto Arg : Args.getArgs()) {
+ printTypeIndex("ArgType", Arg);
+ }
+ return Error::success();
+}
+
+void CVTypeDumper::printMemberAttributes(MemberAttributes Attrs) {
+ return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(),
+ Attrs.getFlags());
+}
+
+void CVTypeDumper::printMemberAttributes(MemberAccess Access, MethodKind Kind,
+ MethodOptions Options) {
+ W->printEnum("AccessSpecifier", uint8_t(Access),
+ makeArrayRef(MemberAccessNames));
+ // Data members will be vanilla. Don't try to print a method kind for them.
+ if (Kind != MethodKind::Vanilla)
+ W->printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames));
+ if (Options != MethodOptions::None) {
+ W->printFlags("MethodOptions", unsigned(Options),
+ makeArrayRef(MethodOptionNames));
+ }
+}
+
+Error CVTypeDumper::visitUnknownMember(const CVRecord<TypeLeafKind> &Record) {
+ W->printHex("UnknownMember", unsigned(Record.Type));
+ return Error::success();
+}
+
+Error CVTypeDumper::visitUnknownType(const CVRecord<TypeLeafKind> &Record) {
+ DictScope S(*W, "UnknownType");
+ W->printEnum("Kind", uint16_t(Record.Type), makeArrayRef(LeafTypeNames));
+ W->printNumber("Length", uint32_t(Record.Data.size()));
+ return Error::success();
+}
+
+Error CVTypeDumper::visitNestedType(NestedTypeRecord &Nested) {
+ DictScope S(*W, "NestedType");
+ printTypeIndex("Type", Nested.getNestedType());
+ W->printString("Name", Nested.getName());
+ Name = Nested.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitOneMethod(OneMethodRecord &Method) {
+ DictScope S(*W, "OneMethod");
+ MethodKind K = Method.getKind();
+ printMemberAttributes(Method.getAccess(), K, Method.getOptions());
+ printTypeIndex("Type", Method.getType());
+ // If virtual, then read the vftable offset.
+ if (Method.isIntroducingVirtual())
+ W->printHex("VFTableOffset", Method.getVFTableOffset());
+ W->printString("Name", Method.getName());
+ Name = Method.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitOverloadedMethod(OverloadedMethodRecord &Method) {
+ DictScope S(*W, "OverloadedMethod");
+ W->printHex("MethodCount", Method.getNumOverloads());
+ printTypeIndex("MethodListIndex", Method.getMethodList());
+ W->printString("Name", Method.getName());
+ Name = Method.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitDataMember(DataMemberRecord &Field) {
+ DictScope S(*W, "DataMember");
+ printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("Type", Field.getType());
+ W->printHex("FieldOffset", Field.getFieldOffset());
+ W->printString("Name", Field.getName());
+ Name = Field.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitStaticDataMember(StaticDataMemberRecord &Field) {
+ DictScope S(*W, "StaticDataMember");
+ printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("Type", Field.getType());
+ W->printString("Name", Field.getName());
+ Name = Field.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitVFPtr(VFPtrRecord &VFTable) {
+ DictScope S(*W, "VFPtr");
+ printTypeIndex("Type", VFTable.getType());
+ return Error::success();
+}
+
+Error CVTypeDumper::visitEnumerator(EnumeratorRecord &Enum) {
+ DictScope S(*W, "Enumerator");
+ printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ W->printNumber("EnumValue", Enum.getValue());
+ W->printString("Name", Enum.getName());
+ Name = Enum.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitBaseClass(BaseClassRecord &Base) {
+ DictScope S(*W, "BaseClass");
+ printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("BaseType", Base.getBaseType());
+ W->printHex("BaseOffset", Base.getBaseOffset());
+ return Error::success();
+}
+
+Error CVTypeDumper::visitVirtualBaseClass(VirtualBaseClassRecord &Base) {
+ DictScope S(*W, "VirtualBaseClass");
+ printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("BaseType", Base.getBaseType());
+ printTypeIndex("VBPtrType", Base.getVBPtrType());
+ W->printHex("VBPtrOffset", Base.getVBPtrOffset());
+ W->printHex("VBTableIndex", Base.getVTableIndex());
+ return Error::success();
+}
+
+Error CVTypeDumper::visitListContinuation(ListContinuationRecord &Cont) {
+ DictScope S(*W, "ListContinuation");
+ printTypeIndex("ContinuationIndex", Cont.getContinuationIndex());
+ return Error::success();
+}
+
+StringRef CVTypeDumper::getTypeName(TypeIndex TI) {
+ if (TI.isNoneType())
+ return "<no type>";
+
+ if (TI.isSimple()) {
+ // This is a simple type.
+ for (const auto &SimpleTypeName : SimpleTypeNames) {
+ if (SimpleTypeName.Value == TI.getSimpleKind()) {
+ if (TI.getSimpleMode() == SimpleTypeMode::Direct)
+ return SimpleTypeName.Name.drop_back(1);
+ // Otherwise, this is a pointer type. We gloss over the distinction
+ // between near, far, 64, 32, etc, and just give a pointer type.
+ return SimpleTypeName.Name;
+ }
+ }
+ return "<unknown simple type>";
+ }
+
+ // User-defined type.
+ StringRef UDTName;
+ unsigned UDTIndex = TI.getIndex() - 0x1000;
+ if (UDTIndex < CVUDTNames.size())
+ return CVUDTNames[UDTIndex];
+
+ return "<unknown UDT>";
+}
+
+void CVTypeDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) {
+ StringRef TypeName;
+ if (!TI.isNoneType())
+ TypeName = getTypeName(TI);
+ if (!TypeName.empty())
+ W->printHex(FieldName, TypeName, TI.getIndex());
+ else
+ W->printHex(FieldName, TI.getIndex());
+}
+
+Error CVTypeDumper::dump(const CVRecord<TypeLeafKind> &Record) {
+ assert(W && "printer should not be null");
+ CVTypeVisitor Visitor(*this);
+
+ if (auto EC = Visitor.visitTypeRecord(Record))
+ return EC;
+ return Error::success();
+}
+
+Error CVTypeDumper::dump(const CVTypeArray &Types) {
+ assert(W && "printer should not be null");
+ CVTypeVisitor Visitor(*this);
+ if (auto EC = Visitor.visitTypeStream(Types))
+ return EC;
+ return Error::success();
+}
+
+Error CVTypeDumper::dump(ArrayRef<uint8_t> Data) {
+ ByteStream<> Stream(Data);
+ CVTypeArray Types;
+ StreamReader Reader(Stream);
+ if (auto EC = Reader.readArray(Types, Reader.getLength()))
+ return EC;
+
+ return dump(Types);
+}
+
+void CVTypeDumper::setPrinter(ScopedPrinter *P) {
+ static ScopedPrinter NullP(llvm::nulls());
+ W = P ? P : &NullP;
+}
diff --git a/lib/DebugInfo/CodeView/TypeRecord.cpp b/lib/DebugInfo/CodeView/TypeRecord.cpp
new file mode 100644
index 000000000000..f63371e8c14f
--- /dev/null
+++ b/lib/DebugInfo/CodeView/TypeRecord.cpp
@@ -0,0 +1,572 @@
+//===-- TypeRecord.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+//===----------------------------------------------------------------------===//
+// Type record deserialization
+//===----------------------------------------------------------------------===//
+
+ErrorOr<MemberPointerInfo>
+MemberPointerInfo::deserialize(ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ if (auto EC = consumeObject(Data, L))
+ return EC;
+
+ TypeIndex T = L->ClassType;
+ uint16_t R = L->Representation;
+ PointerToMemberRepresentation PMR =
+ static_cast<PointerToMemberRepresentation>(R);
+ return MemberPointerInfo(T, PMR);
+}
+
+ErrorOr<ModifierRecord> ModifierRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ if (auto EC = consumeObject(Data, L))
+ return EC;
+
+ TypeIndex M = L->ModifiedType;
+ uint16_t O = L->Modifiers;
+ ModifierOptions MO = static_cast<ModifierOptions>(O);
+ return ModifierRecord(M, MO);
+}
+
+ErrorOr<ProcedureRecord> ProcedureRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ if (auto EC = consumeObject(Data, L))
+ return EC;
+ return ProcedureRecord(L->ReturnType, L->CallConv, L->Options,
+ L->NumParameters, L->ArgListType);
+}
+
+ErrorOr<MemberFunctionRecord>
+MemberFunctionRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ CV_DESERIALIZE(Data, L);
+ return MemberFunctionRecord(L->ReturnType, L->ClassType, L->ThisType,
+ L->CallConv, L->Options, L->NumParameters,
+ L->ArgListType, L->ThisAdjustment);
+}
+
+ErrorOr<MemberFuncIdRecord>
+MemberFuncIdRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
+ return MemberFuncIdRecord(L->ClassType, L->FunctionType, Name);
+}
+
+ErrorOr<ArgListRecord> ArgListRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ if (Kind != TypeRecordKind::StringList && Kind != TypeRecordKind::ArgList)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ const Layout *L = nullptr;
+ ArrayRef<TypeIndex> Indices;
+ CV_DESERIALIZE(Data, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs));
+ return ArgListRecord(Kind, Indices);
+}
+
+ErrorOr<PointerRecord> PointerRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ if (auto EC = consumeObject(Data, L))
+ return EC;
+
+ PointerKind PtrKind = L->getPtrKind();
+ PointerMode Mode = L->getPtrMode();
+ uint32_t Opts = L->Attrs;
+ PointerOptions Options = static_cast<PointerOptions>(Opts);
+ uint8_t Size = L->getPtrSize();
+
+ if (L->isPointerToMember()) {
+ auto E = MemberPointerInfo::deserialize(Data);
+ if (E.getError())
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size, *E);
+ }
+
+ return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size);
+}
+
+ErrorOr<NestedTypeRecord>
+NestedTypeRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
+ return NestedTypeRecord(L->Type, Name);
+}
+
+ErrorOr<ArrayRecord> ArrayRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ uint64_t Size;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name);
+ return ArrayRecord(L->ElementType, L->IndexType, Size, Name);
+}
+
+ErrorOr<ClassRecord> ClassRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ uint64_t Size = 0;
+ StringRef Name;
+ StringRef UniqueName;
+ uint16_t Props;
+ const Layout *L = nullptr;
+
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name,
+ CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName()));
+
+ Props = L->Properties;
+ uint16_t WrtValue = (Props & WinRTKindMask) >> WinRTKindShift;
+ WindowsRTClassKind WRT = static_cast<WindowsRTClassKind>(WrtValue);
+ uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift;
+ HfaKind Hfa = static_cast<HfaKind>(HfaMask);
+
+ ClassOptions Options = static_cast<ClassOptions>(Props);
+ return ClassRecord(Kind, L->MemberCount, Options, Hfa, WRT, L->FieldList,
+ L->DerivedFrom, L->VShape, Size, Name, UniqueName);
+}
+
+ErrorOr<UnionRecord> UnionRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ uint64_t Size = 0;
+ StringRef Name;
+ StringRef UniqueName;
+ uint16_t Props;
+
+ const Layout *L = nullptr;
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name,
+ CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName()));
+
+ Props = L->Properties;
+
+ uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift;
+ HfaKind Hfa = static_cast<HfaKind>(HfaMask);
+ ClassOptions Options = static_cast<ClassOptions>(Props);
+ return UnionRecord(L->MemberCount, Options, Hfa, L->FieldList, Size, Name,
+ UniqueName);
+}
+
+ErrorOr<EnumRecord> EnumRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ StringRef UniqueName;
+ CV_DESERIALIZE(Data, L, Name,
+ CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName()));
+
+ uint16_t P = L->Properties;
+ ClassOptions Options = static_cast<ClassOptions>(P);
+ return EnumRecord(L->NumEnumerators, Options, L->FieldListType, Name,
+ UniqueName, L->UnderlyingType);
+}
+
+ErrorOr<BitFieldRecord> BitFieldRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ CV_DESERIALIZE(Data, L);
+ return BitFieldRecord(L->Type, L->BitSize, L->BitOffset);
+}
+
+ErrorOr<VFTableShapeRecord>
+VFTableShapeRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ if (auto EC = consumeObject(Data, L))
+ return EC;
+
+ std::vector<VFTableSlotKind> Slots;
+ uint16_t Count = L->VFEntryCount;
+ while (Count > 0) {
+ if (Data.empty())
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ // Process up to 2 nibbles at a time (if there are at least 2 remaining)
+ uint8_t Value = Data[0] & 0x0F;
+ Slots.push_back(static_cast<VFTableSlotKind>(Value));
+ if (--Count > 0) {
+ Value = (Data[0] & 0xF0) >> 4;
+ Slots.push_back(static_cast<VFTableSlotKind>(Value));
+ --Count;
+ }
+ Data = Data.slice(1);
+ }
+
+ return VFTableShapeRecord(Slots);
+}
+
+ErrorOr<TypeServer2Record>
+TypeServer2Record::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
+ return TypeServer2Record(StringRef(L->Guid, 16), L->Age, Name);
+}
+
+ErrorOr<StringIdRecord> StringIdRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
+ return StringIdRecord(L->id, Name);
+}
+
+ErrorOr<FuncIdRecord> FuncIdRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
+ return FuncIdRecord(L->ParentScope, L->FunctionType, Name);
+}
+
+ErrorOr<UdtSourceLineRecord>
+UdtSourceLineRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ CV_DESERIALIZE(Data, L);
+ return UdtSourceLineRecord(L->UDT, L->SourceFile, L->LineNumber);
+}
+
+ErrorOr<BuildInfoRecord> BuildInfoRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ ArrayRef<TypeIndex> Indices;
+ CV_DESERIALIZE(Data, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs));
+ return BuildInfoRecord(Indices);
+}
+
+ErrorOr<VFTableRecord> VFTableRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ std::vector<StringRef> Names;
+ CV_DESERIALIZE(Data, L, Name, CV_ARRAY_FIELD_TAIL(Names));
+ return VFTableRecord(L->CompleteClass, L->OverriddenVFTable, L->VFPtrOffset,
+ Name, Names);
+}
+
+ErrorOr<OneMethodRecord> OneMethodRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ int32_t VFTableOffset = -1;
+
+ CV_DESERIALIZE(Data, L, CV_CONDITIONAL_FIELD(VFTableOffset,
+ L->Attrs.isIntroducedVirtual()),
+ Name);
+
+ MethodOptions Options = L->Attrs.getFlags();
+ MethodKind MethKind = L->Attrs.getMethodKind();
+ MemberAccess Access = L->Attrs.getAccess();
+ OneMethodRecord Method(L->Type, MethKind, Options, Access, VFTableOffset,
+ Name);
+ // Validate the vftable offset.
+ if (Method.isIntroducingVirtual() && Method.getVFTableOffset() < 0)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ return Method;
+}
+
+ErrorOr<MethodOverloadListRecord>
+MethodOverloadListRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ std::vector<OneMethodRecord> Methods;
+ while (!Data.empty()) {
+ const Layout *L = nullptr;
+ int32_t VFTableOffset = -1;
+ CV_DESERIALIZE(Data, L, CV_CONDITIONAL_FIELD(
+ VFTableOffset, L->Attrs.isIntroducedVirtual()));
+
+ MethodOptions Options = L->Attrs.getFlags();
+ MethodKind MethKind = L->Attrs.getMethodKind();
+ MemberAccess Access = L->Attrs.getAccess();
+
+ Methods.emplace_back(L->Type, MethKind, Options, Access, VFTableOffset,
+ StringRef());
+
+ // Validate the vftable offset.
+ auto &Method = Methods.back();
+ if (Method.isIntroducingVirtual() && Method.getVFTableOffset() < 0)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ }
+ return MethodOverloadListRecord(Methods);
+}
+
+ErrorOr<OverloadedMethodRecord>
+OverloadedMethodRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
+ return OverloadedMethodRecord(L->MethodCount, L->MethList, Name);
+}
+
+ErrorOr<DataMemberRecord>
+DataMemberRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ uint64_t Offset;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset), Name);
+ return DataMemberRecord(L->Attrs.getAccess(), L->Type, Offset, Name);
+}
+
+ErrorOr<StaticDataMemberRecord>
+StaticDataMemberRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
+ return StaticDataMemberRecord(L->Attrs.getAccess(), L->Type, Name);
+}
+
+ErrorOr<EnumeratorRecord>
+EnumeratorRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ APSInt Value;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Value, Name);
+ return EnumeratorRecord(L->Attrs.getAccess(), Value, Name);
+}
+
+ErrorOr<VFPtrRecord> VFPtrRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ if (auto EC = consumeObject(Data, L))
+ return EC;
+ return VFPtrRecord(L->Type);
+}
+
+ErrorOr<BaseClassRecord> BaseClassRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ uint64_t Offset;
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset));
+ return BaseClassRecord(L->Attrs.getAccess(), L->BaseType, Offset);
+}
+
+ErrorOr<VirtualBaseClassRecord>
+VirtualBaseClassRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ uint64_t Offset;
+ uint64_t Index;
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset), CV_NUMERIC_FIELD(Index));
+ return VirtualBaseClassRecord(L->Attrs.getAccess(), L->BaseType, L->VBPtrType,
+ Offset, Index);
+}
+
+ErrorOr<ListContinuationRecord>
+ListContinuationRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ CV_DESERIALIZE(Data, L);
+ return ListContinuationRecord(L->ContinuationIndex);
+}
+
+//===----------------------------------------------------------------------===//
+// Type index remapping
+//===----------------------------------------------------------------------===//
+
+static bool remapIndex(ArrayRef<TypeIndex> IndexMap, TypeIndex &Idx) {
+ // Simple types are unchanged.
+ if (Idx.isSimple())
+ return true;
+ unsigned MapPos = Idx.getIndex() - TypeIndex::FirstNonSimpleIndex;
+ if (MapPos < IndexMap.size()) {
+ Idx = IndexMap[MapPos];
+ return true;
+ }
+
+ // This type index is invalid. Remap this to "not translated by cvpack",
+ // and return failure.
+ Idx = TypeIndex(SimpleTypeKind::NotTranslated, SimpleTypeMode::Direct);
+ return false;
+}
+
+bool ModifierRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, ModifiedType);
+}
+
+bool ProcedureRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, ReturnType);
+ Success &= remapIndex(IndexMap, ArgumentList);
+ return Success;
+}
+
+bool MemberFunctionRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, ReturnType);
+ Success &= remapIndex(IndexMap, ClassType);
+ Success &= remapIndex(IndexMap, ThisType);
+ Success &= remapIndex(IndexMap, ArgumentList);
+ return Success;
+}
+
+bool MemberFuncIdRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, ClassType);
+ Success &= remapIndex(IndexMap, FunctionType);
+ return Success;
+}
+
+bool ArgListRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ for (TypeIndex &Str : StringIndices)
+ Success &= remapIndex(IndexMap, Str);
+ return Success;
+}
+
+bool MemberPointerInfo::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, ContainingType);
+}
+
+bool PointerRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, ReferentType);
+ if (isPointerToMember())
+ Success &= MemberInfo.remapTypeIndices(IndexMap);
+ return Success;
+}
+
+bool NestedTypeRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, Type);
+}
+
+bool ArrayRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, ElementType);
+ Success &= remapIndex(IndexMap, IndexType);
+ return Success;
+}
+
+bool TagRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, FieldList);
+}
+
+bool ClassRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= TagRecord::remapTypeIndices(IndexMap);
+ Success &= remapIndex(IndexMap, DerivationList);
+ Success &= remapIndex(IndexMap, VTableShape);
+ return Success;
+}
+
+bool EnumRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= TagRecord::remapTypeIndices(IndexMap);
+ Success &= remapIndex(IndexMap, UnderlyingType);
+ return Success;
+}
+
+bool BitFieldRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, Type);
+}
+
+bool VFTableShapeRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return true;
+}
+
+bool TypeServer2Record::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return true;
+}
+
+bool StringIdRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, Id);
+}
+
+bool FuncIdRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, ParentScope);
+ Success &= remapIndex(IndexMap, FunctionType);
+ return Success;
+}
+
+bool UdtSourceLineRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, UDT);
+ Success &= remapIndex(IndexMap, SourceFile);
+ return Success;
+}
+
+bool UdtModSourceLineRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, UDT);
+ Success &= remapIndex(IndexMap, SourceFile);
+ return Success;
+}
+
+bool BuildInfoRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ for (TypeIndex &Arg : ArgIndices)
+ Success &= remapIndex(IndexMap, Arg);
+ return Success;
+}
+
+bool VFTableRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, CompleteClass);
+ Success &= remapIndex(IndexMap, OverriddenVFTable);
+ return Success;
+}
+
+bool OneMethodRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, Type);
+ return Success;
+}
+
+bool MethodOverloadListRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ for (OneMethodRecord &Meth : Methods)
+ if ((Success = Meth.remapTypeIndices(IndexMap)))
+ return Success;
+ return Success;
+}
+
+bool OverloadedMethodRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, MethodList);
+}
+
+bool DataMemberRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, Type);
+}
+
+bool StaticDataMemberRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, Type);
+}
+
+bool EnumeratorRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return true;
+}
+
+bool VFPtrRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, Type);
+}
+
+bool BaseClassRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, Type);
+}
+
+bool VirtualBaseClassRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, BaseType);
+ Success &= remapIndex(IndexMap, VBPtrType);
+ return Success;
+}
+
+bool ListContinuationRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, ContinuationIndex);
+}
diff --git a/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp b/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp
index cbf464fd7668..112612cc85ea 100644
--- a/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp
+++ b/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp
@@ -12,8 +12,8 @@
using namespace llvm;
using namespace codeview;
-TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind) : Stream(Buffer),
- Writer(Stream) {
+TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind)
+ : Stream(Buffer), Writer(Stream) {
writeTypeRecordKind(Kind);
}
@@ -60,50 +60,50 @@ void TypeRecordBuilder::writeEncodedInteger(int64_t Value) {
void TypeRecordBuilder::writeEncodedSignedInteger(int64_t Value) {
if (Value >= std::numeric_limits<int8_t>::min() &&
Value <= std::numeric_limits<int8_t>::max()) {
- writeUInt16(static_cast<uint16_t>(TypeRecordKind::SByte));
+ writeUInt16(LF_CHAR);
writeInt16(static_cast<int8_t>(Value));
} else if (Value >= std::numeric_limits<int16_t>::min() &&
Value <= std::numeric_limits<int16_t>::max()) {
- writeUInt16(static_cast<uint16_t>(TypeRecordKind::Int16));
+ writeUInt16(LF_SHORT);
writeInt16(static_cast<int16_t>(Value));
} else if (Value >= std::numeric_limits<int32_t>::min() &&
Value <= std::numeric_limits<int32_t>::max()) {
- writeUInt16(static_cast<uint32_t>(TypeRecordKind::Int32));
+ writeUInt16(LF_LONG);
writeInt32(static_cast<int32_t>(Value));
} else {
- writeUInt16(static_cast<uint16_t>(TypeRecordKind::Int64));
+ writeUInt16(LF_QUADWORD);
writeInt64(Value);
}
}
void TypeRecordBuilder::writeEncodedUnsignedInteger(uint64_t Value) {
- if (Value < static_cast<uint16_t>(TypeRecordKind::SByte)) {
+ if (Value < LF_CHAR) {
writeUInt16(static_cast<uint16_t>(Value));
} else if (Value <= std::numeric_limits<uint16_t>::max()) {
- writeUInt16(static_cast<uint16_t>(TypeRecordKind::UInt16));
+ writeUInt16(LF_USHORT);
writeUInt16(static_cast<uint16_t>(Value));
} else if (Value <= std::numeric_limits<uint32_t>::max()) {
- writeUInt16(static_cast<uint16_t>(TypeRecordKind::UInt32));
+ writeUInt16(LF_ULONG);
writeUInt32(static_cast<uint32_t>(Value));
} else {
- writeUInt16(static_cast<uint16_t>(TypeRecordKind::UInt64));
+ writeUInt16(LF_UQUADWORD);
writeUInt64(Value);
}
}
-void TypeRecordBuilder::writeNullTerminatedString(const char *Value) {
- assert(Value != nullptr);
-
- size_t Length = strlen(Value);
- Stream.write(Value, Length);
- writeUInt8(0);
-}
-
void TypeRecordBuilder::writeNullTerminatedString(StringRef Value) {
+ // Microsoft's linker seems to have trouble with symbol names longer than
+ // 0xffd8 bytes.
+ Value = Value.substr(0, 0xffd8);
Stream.write(Value.data(), Value.size());
writeUInt8(0);
}
+void TypeRecordBuilder::writeGuid(StringRef Guid) {
+ assert(Guid.size() == 16);
+ Stream.write(Guid.data(), 16);
+}
+
void TypeRecordBuilder::writeTypeIndex(TypeIndex TypeInd) {
writeUInt32(TypeInd.getIndex());
}
diff --git a/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
new file mode 100644
index 000000000000..ebfda2462be1
--- /dev/null
+++ b/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
@@ -0,0 +1,149 @@
+//===-- TypeStreamMerger.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
+#include "llvm/DebugInfo/CodeView/StreamRef.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+
+/// Implementation of CodeView type stream merging.
+///
+/// A CodeView type stream is a series of records that reference each other
+/// through type indices. A type index is either "simple", meaning it is less
+/// than 0x1000 and refers to a builtin type, or it is complex, meaning it
+/// refers to a prior type record in the current stream. The type index of a
+/// record is equal to the number of records before it in the stream plus
+/// 0x1000.
+///
+/// Type records are only allowed to use type indices smaller than their own, so
+/// a type stream is effectively a topologically sorted DAG. Cycles occuring in
+/// the type graph of the source program are resolved with forward declarations
+/// of composite types. This class implements the following type stream merging
+/// algorithm, which relies on this DAG structure:
+///
+/// - Begin with a new empty stream, and a new empty hash table that maps from
+/// type record contents to new type index.
+/// - For each new type stream, maintain a map from source type index to
+/// destination type index.
+/// - For each record, copy it and rewrite its type indices to be valid in the
+/// destination type stream.
+/// - If the new type record is not already present in the destination stream
+/// hash table, append it to the destination type stream, assign it the next
+/// type index, and update the two hash tables.
+/// - If the type record already exists in the destination stream, discard it
+/// and update the type index map to forward the source type index to the
+/// existing destination type index.
+class TypeStreamMerger : public TypeVisitorCallbacks {
+public:
+ TypeStreamMerger(TypeTableBuilder &DestStream) : DestStream(DestStream) {
+ assert(!hadError());
+ }
+
+/// TypeVisitorCallbacks overrides.
+#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 "llvm/DebugInfo/CodeView/TypeRecords.def"
+
+ Error visitUnknownType(const CVRecord<TypeLeafKind> &Record) override;
+
+ Error visitTypeBegin(const CVRecord<TypeLeafKind> &Record) override;
+ Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override;
+
+ Error visitFieldListEnd(const CVRecord<TypeLeafKind> &Record) override;
+
+ bool mergeStream(const CVTypeArray &Types);
+
+private:
+ bool hadError() { return FoundBadTypeIndex; }
+
+ bool FoundBadTypeIndex = false;
+
+ FieldListRecordBuilder FieldBuilder;
+
+ TypeTableBuilder &DestStream;
+
+ size_t BeginIndexMapSize = 0;
+
+ /// Map from source type index to destination type index. Indexed by source
+ /// type index minus 0x1000.
+ SmallVector<TypeIndex, 0> IndexMap;
+};
+
+} // end anonymous namespace
+
+Error TypeStreamMerger::visitTypeBegin(const CVRecord<TypeLeafKind> &Rec) {
+ BeginIndexMapSize = IndexMap.size();
+ return Error::success();
+}
+
+Error TypeStreamMerger::visitTypeEnd(const CVRecord<TypeLeafKind> &Rec) {
+ assert(IndexMap.size() == BeginIndexMapSize + 1);
+ return Error::success();
+}
+
+Error TypeStreamMerger::visitFieldListEnd(const CVRecord<TypeLeafKind> &Rec) {
+ IndexMap.push_back(DestStream.writeFieldList(FieldBuilder));
+ FieldBuilder.reset();
+ return Error::success();
+}
+
+#define TYPE_RECORD(EnumName, EnumVal, Name) \
+ Error TypeStreamMerger::visit##Name(Name##Record &Record) { \
+ FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \
+ IndexMap.push_back(DestStream.write##Name(Record)); \
+ return Error::success(); \
+ }
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ Error TypeStreamMerger::visit##Name(Name##Record &Record) { \
+ FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \
+ FieldBuilder.write##Name(Record); \
+ return Error::success(); \
+ }
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+
+Error TypeStreamMerger::visitUnknownType(const CVRecord<TypeLeafKind> &Rec) {
+ // We failed to translate a type. Translate this index as "not translated".
+ IndexMap.push_back(
+ TypeIndex(SimpleTypeKind::NotTranslated, SimpleTypeMode::Direct));
+ return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);
+}
+
+bool TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
+ assert(IndexMap.empty());
+ CVTypeVisitor Visitor(*this);
+ if (auto EC = Visitor.visitTypeStream(Types)) {
+ consumeError(std::move(EC));
+ return false;
+ }
+ IndexMap.clear();
+ return !hadError();
+}
+
+bool llvm::codeview::mergeTypeStreams(TypeTableBuilder &DestStream,
+ const CVTypeArray &Types) {
+ return TypeStreamMerger(DestStream).mergeStream(Types);
+}
diff --git a/lib/DebugInfo/CodeView/TypeTableBuilder.cpp b/lib/DebugInfo/CodeView/TypeTableBuilder.cpp
index 4af5dcaf7228..647538ee8ceb 100644
--- a/lib/DebugInfo/CodeView/TypeTableBuilder.cpp
+++ b/lib/DebugInfo/CodeView/TypeTableBuilder.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
#include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
@@ -18,42 +17,21 @@
using namespace llvm;
using namespace codeview;
-namespace {
-
-const int PointerKindShift = 0;
-const int PointerModeShift = 5;
-const int PointerSizeShift = 13;
-
-const int ClassHfaKindShift = 11;
-const int ClassWindowsRTClassKindShift = 14;
-
-void writePointerBase(TypeRecordBuilder &Builder,
- const PointerRecordBase &Record) {
- Builder.writeTypeIndex(Record.getReferentType());
- uint32_t flags =
- static_cast<uint32_t>(Record.getOptions()) |
- (Record.getSize() << PointerSizeShift) |
- (static_cast<uint32_t>(Record.getMode()) << PointerModeShift) |
- (static_cast<uint32_t>(Record.getPointerKind()) << PointerKindShift);
- Builder.writeUInt32(flags);
-}
-}
-
TypeTableBuilder::TypeTableBuilder() {}
TypeTableBuilder::~TypeTableBuilder() {}
TypeIndex TypeTableBuilder::writeModifier(const ModifierRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::Modifier);
+ TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getModifiedType());
- Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions()));
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getModifiers()));
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::Procedure);
+ TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getReturnType());
Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv()));
@@ -66,7 +44,7 @@ TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) {
TypeIndex
TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::MemberFunction);
+ TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getReturnType());
Builder.writeTypeIndex(Record.getClassType());
@@ -80,12 +58,11 @@ TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) {
return writeRecord(Builder);
}
-TypeIndex
-TypeTableBuilder::writeArgumentList(const ArgumentListRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::ArgumentList);
+TypeIndex TypeTableBuilder::writeArgList(const ArgListRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
- Builder.writeUInt32(Record.getArgumentTypes().size());
- for (TypeIndex TI : Record.getArgumentTypes()) {
+ Builder.writeUInt32(Record.getIndices().size());
+ for (TypeIndex TI : Record.getIndices()) {
Builder.writeTypeIndex(TI);
}
@@ -93,27 +70,28 @@ TypeTableBuilder::writeArgumentList(const ArgumentListRecord &Record) {
}
TypeIndex TypeTableBuilder::writePointer(const PointerRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::Pointer);
-
- writePointerBase(Builder, Record);
-
- return writeRecord(Builder);
-}
-
-TypeIndex
-TypeTableBuilder::writePointerToMember(const PointerToMemberRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::Pointer);
+ TypeRecordBuilder Builder(Record.getKind());
- writePointerBase(Builder, Record);
+ Builder.writeTypeIndex(Record.getReferentType());
+ uint32_t flags = static_cast<uint32_t>(Record.getOptions()) |
+ (Record.getSize() << PointerRecord::PointerSizeShift) |
+ (static_cast<uint32_t>(Record.getMode())
+ << PointerRecord::PointerModeShift) |
+ (static_cast<uint32_t>(Record.getPointerKind())
+ << PointerRecord::PointerKindShift);
+ Builder.writeUInt32(flags);
- Builder.writeTypeIndex(Record.getContainingType());
- Builder.writeUInt16(static_cast<uint16_t>(Record.getRepresentation()));
+ if (Record.isPointerToMember()) {
+ const MemberPointerInfo &M = Record.getMemberInfo();
+ Builder.writeTypeIndex(M.getContainingType());
+ Builder.writeUInt16(static_cast<uint16_t>(M.getRepresentation()));
+ }
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::Array);
+ TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getElementType());
Builder.writeTypeIndex(Record.getIndexType());
@@ -123,28 +101,23 @@ TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) {
return writeRecord(Builder);
}
-TypeIndex TypeTableBuilder::writeAggregate(const AggregateRecord &Record) {
- assert((Record.getKind() == TypeRecordKind::Structure) ||
+TypeIndex TypeTableBuilder::writeClass(const ClassRecord &Record) {
+ assert((Record.getKind() == TypeRecordKind::Struct) ||
(Record.getKind() == TypeRecordKind::Class) ||
- (Record.getKind() == TypeRecordKind::Union));
+ (Record.getKind() == TypeRecordKind::Interface));
TypeRecordBuilder Builder(Record.getKind());
Builder.writeUInt16(Record.getMemberCount());
uint16_t Flags =
static_cast<uint16_t>(Record.getOptions()) |
- (static_cast<uint16_t>(Record.getHfa()) << ClassHfaKindShift) |
+ (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift) |
(static_cast<uint16_t>(Record.getWinRTKind())
- << ClassWindowsRTClassKindShift);
+ << ClassRecord::WinRTKindShift);
Builder.writeUInt16(Flags);
Builder.writeTypeIndex(Record.getFieldList());
- if (Record.getKind() != TypeRecordKind::Union) {
- Builder.writeTypeIndex(Record.getDerivationList());
- Builder.writeTypeIndex(Record.getVTableShape());
- } else {
- assert(Record.getDerivationList() == TypeIndex());
- assert(Record.getVTableShape() == TypeIndex());
- }
+ Builder.writeTypeIndex(Record.getDerivationList());
+ Builder.writeTypeIndex(Record.getVTableShape());
Builder.writeEncodedUnsignedInteger(Record.getSize());
Builder.writeNullTerminatedString(Record.getName());
if ((Record.getOptions() & ClassOptions::HasUniqueName) !=
@@ -155,8 +128,25 @@ TypeIndex TypeTableBuilder::writeAggregate(const AggregateRecord &Record) {
return writeRecord(Builder);
}
+TypeIndex TypeTableBuilder::writeUnion(const UnionRecord &Record) {
+ TypeRecordBuilder Builder(TypeRecordKind::Union);
+ Builder.writeUInt16(Record.getMemberCount());
+ uint16_t Flags =
+ static_cast<uint16_t>(Record.getOptions()) |
+ (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift);
+ Builder.writeUInt16(Flags);
+ Builder.writeTypeIndex(Record.getFieldList());
+ Builder.writeEncodedUnsignedInteger(Record.getSize());
+ Builder.writeNullTerminatedString(Record.getName());
+ if ((Record.getOptions() & ClassOptions::HasUniqueName) !=
+ ClassOptions::None) {
+ Builder.writeNullTerminatedString(Record.getUniqueName());
+ }
+ return writeRecord(Builder);
+}
+
TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::Enum);
+ TypeRecordBuilder Builder(Record.getKind());
Builder.writeUInt16(Record.getMemberCount());
Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions()));
@@ -172,7 +162,7 @@ TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) {
}
TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::BitField);
+ TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getType());
Builder.writeUInt8(Record.getBitSize());
@@ -181,11 +171,11 @@ TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) {
return writeRecord(Builder);
}
-TypeIndex TypeTableBuilder::writeVirtualTableShape(
- const VirtualTableShapeRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::VirtualTableShape);
+TypeIndex
+TypeTableBuilder::writeVFTableShape(const VFTableShapeRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
- ArrayRef<VirtualTableSlotKind> Slots = Record.getSlots();
+ ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
Builder.writeUInt16(Slots.size());
for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
@@ -199,19 +189,115 @@ TypeIndex TypeTableBuilder::writeVirtualTableShape(
return writeRecord(Builder);
}
+TypeIndex
+TypeTableBuilder::writeVFTable(const VFTableRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ Builder.writeTypeIndex(Record.getCompleteClass());
+ Builder.writeTypeIndex(Record.getOverriddenVTable());
+ Builder.writeUInt32(Record.getVFPtrOffset());
+
+ // Sum up the lengths of the null-terminated names.
+ size_t NamesLen = Record.getName().size() + 1;
+ for (StringRef MethodName : Record.getMethodNames())
+ NamesLen += MethodName.size() + 1;
+
+ Builder.writeUInt32(NamesLen);
+ Builder.writeNullTerminatedString(Record.getName());
+ for (StringRef MethodName : Record.getMethodNames())
+ Builder.writeNullTerminatedString(MethodName);
+
+ return writeRecord(Builder);
+}
+
+TypeIndex TypeTableBuilder::writeStringId(const StringIdRecord &Record) {
+ TypeRecordBuilder Builder(TypeRecordKind::StringId);
+ Builder.writeTypeIndex(Record.getId());
+ Builder.writeNullTerminatedString(Record.getString());
+ return writeRecord(Builder);
+}
+
+TypeIndex
+TypeTableBuilder::writeUdtSourceLine(const UdtSourceLineRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ Builder.writeTypeIndex(Record.getUDT());
+ Builder.writeTypeIndex(Record.getSourceFile());
+ Builder.writeUInt32(Record.getLineNumber());
+ return writeRecord(Builder);
+}
+
+TypeIndex
+TypeTableBuilder::writeUdtModSourceLine(const UdtModSourceLineRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ Builder.writeTypeIndex(Record.getUDT());
+ Builder.writeTypeIndex(Record.getSourceFile());
+ Builder.writeUInt32(Record.getLineNumber());
+ Builder.writeUInt16(Record.getModule());
+ return writeRecord(Builder);
+}
+
+TypeIndex TypeTableBuilder::writeFuncId(const FuncIdRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ Builder.writeTypeIndex(Record.getParentScope());
+ Builder.writeTypeIndex(Record.getFunctionType());
+ Builder.writeNullTerminatedString(Record.getName());
+ return writeRecord(Builder);
+}
+
+TypeIndex
+TypeTableBuilder::writeMemberFuncId(const MemberFuncIdRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ Builder.writeTypeIndex(Record.getClassType());
+ Builder.writeTypeIndex(Record.getFunctionType());
+ Builder.writeNullTerminatedString(Record.getName());
+ return writeRecord(Builder);
+}
+
+TypeIndex
+TypeTableBuilder::writeBuildInfo(const BuildInfoRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ assert(Record.getArgs().size() <= UINT16_MAX);
+ Builder.writeUInt16(Record.getArgs().size());
+ for (TypeIndex Arg : Record.getArgs())
+ Builder.writeTypeIndex(Arg);
+ return writeRecord(Builder);
+}
+
TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder &Builder) {
return writeRecord(Builder.str());
}
TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) {
- // TODO: Split the list into multiple records if it's longer than 64KB, using
- // a subrecord of TypeRecordKind::Index to chain the records together.
- return writeRecord(FieldList.str());
+ return FieldList.writeListRecord(*this);
}
-TypeIndex
-TypeTableBuilder::writeMethodList(MethodListRecordBuilder &MethodList) {
+TypeIndex TypeTableBuilder::writeMethodOverloadList(
+ const MethodOverloadListRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ for (const OneMethodRecord &Method : Record.getMethods()) {
+ uint16_t Flags = static_cast<uint16_t>(Method.getAccess());
+ Flags |= static_cast<uint16_t>(Method.getKind())
+ << MemberAttributes::MethodKindShift;
+ Flags |= static_cast<uint16_t>(Method.getOptions());
+ Builder.writeUInt16(Flags);
+ Builder.writeUInt16(0); // padding
+ Builder.writeTypeIndex(Method.getType());
+ if (Method.isIntroducingVirtual()) {
+ assert(Method.getVFTableOffset() >= 0);
+ Builder.writeInt32(Method.getVFTableOffset());
+ } else {
+ assert(Method.getVFTableOffset() == -1);
+ }
+ }
+
// TODO: Split the list into multiple records if it's longer than 64KB, using
// a subrecord of TypeRecordKind::Index to chain the records together.
- return writeRecord(MethodList.str());
+ return writeRecord(Builder);
+}
+
+TypeIndex TypeTableBuilder::writeTypeServer2(const TypeServer2Record &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ Builder.writeGuid(Record.getGuid());
+ Builder.writeUInt32(Record.getAge());
+ Builder.writeNullTerminatedString(Record.getName());
+ return writeRecord(Builder);
}
diff --git a/lib/DebugInfo/DWARF/DWARFContext.cpp b/lib/DebugInfo/DWARF/DWARFContext.cpp
index a4195b75c47d..e8ea71b325ae 100644
--- a/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -13,8 +13,11 @@
#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/RelocVisitor.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/ELF.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -72,7 +75,7 @@ static void dumpAccelSection(raw_ostream &OS, StringRef Name,
Accel.dump(OS);
}
-void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
+void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH) {
if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) {
OS << ".debug_abbrev contents:\n";
getDebugAbbrev()->dump(OS);
@@ -125,6 +128,10 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
if (DumpType == DIDT_All || DumpType == DIDT_Frames) {
OS << "\n.debug_frame contents:\n";
getDebugFrame()->dump(OS);
+ if (DumpEH) {
+ OS << "\n.eh_frame contents:\n";
+ getEHFrame()->dump(OS);
+ }
}
if (DumpType == DIDT_All || DumpType == DIDT_Macro) {
@@ -355,7 +362,18 @@ const DWARFDebugFrame *DWARFContext::getDebugFrame() {
// http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html
DataExtractor debugFrameData(getDebugFrameSection(), isLittleEndian(),
getAddressSize());
- DebugFrame.reset(new DWARFDebugFrame());
+ DebugFrame.reset(new DWARFDebugFrame(false /* IsEH */));
+ DebugFrame->parse(debugFrameData);
+ return DebugFrame.get();
+}
+
+const DWARFDebugFrame *DWARFContext::getEHFrame() {
+ if (EHFrame)
+ return EHFrame.get();
+
+ DataExtractor debugFrameData(getEHFrameSection(), isLittleEndian(),
+ getAddressSize());
+ DebugFrame.reset(new DWARFDebugFrame(true /* IsEH */));
DebugFrame->parse(debugFrameData);
return DebugFrame.get();
}
@@ -575,8 +593,8 @@ DWARFContext::getInliningInfoForAddress(uint64_t Address,
return InliningInfo;
}
-static bool consumeCompressedDebugSectionHeader(StringRef &data,
- uint64_t &OriginalSize) {
+static bool consumeCompressedGnuHeader(StringRef &data,
+ uint64_t &OriginalSize) {
// Consume "ZLIB" prefix.
if (!data.startswith("ZLIB"))
return false;
@@ -591,6 +609,50 @@ static bool consumeCompressedDebugSectionHeader(StringRef &data,
return true;
}
+static bool consumeCompressedZLibHeader(StringRef &Data, uint64_t &OriginalSize,
+ bool IsLE, bool Is64Bit) {
+ using namespace ELF;
+ uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr);
+ if (Data.size() < HdrSize)
+ return false;
+
+ DataExtractor Extractor(Data, IsLE, 0);
+ uint32_t Offset = 0;
+ if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word)
+ : sizeof(Elf32_Word)) !=
+ ELFCOMPRESS_ZLIB)
+ return false;
+
+ // Skip Elf64_Chdr::ch_reserved field.
+ if (Is64Bit)
+ Offset += sizeof(Elf64_Word);
+
+ OriginalSize = Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Xword)
+ : sizeof(Elf32_Word));
+ Data = Data.substr(HdrSize);
+ return true;
+}
+
+static bool tryDecompress(StringRef &Name, StringRef &Data,
+ SmallString<32> &Out, bool ZLibStyle, bool IsLE,
+ bool Is64Bit) {
+ if (!zlib::isAvailable())
+ return false;
+
+ uint64_t OriginalSize;
+ bool Result =
+ ZLibStyle ? consumeCompressedZLibHeader(Data, OriginalSize, IsLE, Is64Bit)
+ : consumeCompressedGnuHeader(Data, OriginalSize);
+
+ if (!Result || zlib::uncompress(Data, Out, OriginalSize) != zlib::StatusOK)
+ return false;
+
+ // gnu-style names are started from "z", consume that.
+ if (!ZLibStyle)
+ Name = Name.substr(1);
+ return true;
+}
+
DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj,
const LoadedObjectInfo *L)
: IsLittleEndian(Obj.isLittleEndian()),
@@ -616,20 +678,13 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj,
name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes.
- // Check if debug info section is compressed with zlib.
- if (name.startswith("zdebug_")) {
- uint64_t OriginalSize;
- if (!zlib::isAvailable() ||
- !consumeCompressedDebugSectionHeader(data, OriginalSize))
- continue;
- UncompressedSections.resize(UncompressedSections.size() + 1);
- if (zlib::uncompress(data, UncompressedSections.back(), OriginalSize) !=
- zlib::StatusOK) {
- UncompressedSections.pop_back();
+ bool ZLibStyleCompressed = Section.isCompressed();
+ if (ZLibStyleCompressed || name.startswith("zdebug_")) {
+ SmallString<32> Out;
+ if (!tryDecompress(name, data, Out, ZLibStyleCompressed, IsLittleEndian,
+ AddressSize == 8))
continue;
- }
- // Make data point to uncompressed section contents and save its contents.
- name = name.substr(1);
+ UncompressedSections.emplace_back(std::move(Out));
data = UncompressedSections.back();
}
@@ -641,6 +696,7 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj,
.Case("debug_line", &LineSection.Data)
.Case("debug_aranges", &ARangeSection)
.Case("debug_frame", &DebugFrameSection)
+ .Case("eh_frame", &EHFrameSection)
.Case("debug_str", &StringSection)
.Case("debug_ranges", &RangeSection)
.Case("debug_macinfo", &MacinfoSection)
@@ -739,15 +795,29 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj,
// First calculate the address of the symbol or section as it appears
// in the objct file
if (Sym != Obj.symbol_end()) {
- ErrorOr<uint64_t> SymAddrOrErr = Sym->getAddress();
- if (std::error_code EC = SymAddrOrErr.getError()) {
+ Expected<uint64_t> SymAddrOrErr = Sym->getAddress();
+ if (!SymAddrOrErr) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ logAllUnhandledErrors(SymAddrOrErr.takeError(), OS, "");
+ OS.flush();
errs() << "error: failed to compute symbol address: "
- << EC.message() << '\n';
+ << Buf << '\n';
continue;
}
SymAddr = *SymAddrOrErr;
// Also remember what section this symbol is in for later
- RSec = *Sym->getSection();
+ auto SectOrErr = Sym->getSection();
+ if (!SectOrErr) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ logAllUnhandledErrors(SectOrErr.takeError(), OS, "");
+ OS.flush();
+ errs() << "error: failed to get symbol section: "
+ << Buf << '\n';
+ continue;
+ }
+ RSec = *SectOrErr;
} else if (auto *MObj = dyn_cast<MachOObjectFile>(&Obj)) {
// MachO also has relocations that point to sections and
// scattered relocations.
diff --git a/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
index 1aa31be71fee..9b6a9a788230 100644
--- a/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
@@ -10,7 +10,9 @@
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Dwarf.h"
@@ -18,6 +20,7 @@
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
+#include <utility>
#include <vector>
using namespace llvm;
@@ -160,18 +163,26 @@ void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset,
case DW_CFA_offset_extended:
case DW_CFA_register:
case DW_CFA_def_cfa:
- case DW_CFA_val_offset:
+ case DW_CFA_val_offset: {
// Operands: ULEB128, ULEB128
- addInstruction(Opcode, Data.getULEB128(Offset),
- Data.getULEB128(Offset));
+ // Note: We can not embed getULEB128 directly into function
+ // argument list. getULEB128 changes Offset and order of evaluation
+ // for arguments is unspecified.
+ auto op1 = Data.getULEB128(Offset);
+ auto op2 = Data.getULEB128(Offset);
+ addInstruction(Opcode, op1, op2);
break;
+ }
case DW_CFA_offset_extended_sf:
case DW_CFA_def_cfa_sf:
- case DW_CFA_val_offset_sf:
+ case DW_CFA_val_offset_sf: {
// Operands: ULEB128, SLEB128
- addInstruction(Opcode, Data.getULEB128(Offset),
- Data.getSLEB128(Offset));
+ // Note: see comment for the previous case
+ auto op1 = Data.getULEB128(Offset);
+ auto op2 = (uint64_t)Data.getSLEB128(Offset);
+ addInstruction(Opcode, op1, op2);
break;
+ }
case DW_CFA_def_cfa_expression:
case DW_CFA_expression:
case DW_CFA_val_expression:
@@ -191,19 +202,30 @@ public:
CIE(uint64_t Offset, uint64_t Length, uint8_t Version,
SmallString<8> Augmentation, uint8_t AddressSize,
uint8_t SegmentDescriptorSize, uint64_t CodeAlignmentFactor,
- int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister)
+ int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister,
+ SmallString<8> AugmentationData, uint32_t FDEPointerEncoding,
+ uint32_t LSDAPointerEncoding)
: FrameEntry(FK_CIE, Offset, Length), Version(Version),
- Augmentation(std::move(Augmentation)),
- AddressSize(AddressSize),
+ Augmentation(std::move(Augmentation)), AddressSize(AddressSize),
SegmentDescriptorSize(SegmentDescriptorSize),
CodeAlignmentFactor(CodeAlignmentFactor),
DataAlignmentFactor(DataAlignmentFactor),
- ReturnAddressRegister(ReturnAddressRegister) {}
+ ReturnAddressRegister(ReturnAddressRegister),
+ AugmentationData(std::move(AugmentationData)),
+ FDEPointerEncoding(FDEPointerEncoding),
+ LSDAPointerEncoding(LSDAPointerEncoding) {}
~CIE() override {}
+ StringRef getAugmentationString() const { return Augmentation; }
uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; }
int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; }
+ uint32_t getFDEPointerEncoding() const {
+ return FDEPointerEncoding;
+ }
+ uint32_t getLSDAPointerEncoding() const {
+ return LSDAPointerEncoding;
+ }
void dumpHeader(raw_ostream &OS) const override {
OS << format("%08x %08x %08x CIE",
@@ -223,6 +245,12 @@ public:
(int32_t)DataAlignmentFactor);
OS << format(" Return address column: %d\n",
(int32_t)ReturnAddressRegister);
+ if (!AugmentationData.empty()) {
+ OS << " Augmentation data: ";
+ for (uint8_t Byte : AugmentationData)
+ OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf);
+ OS << "\n";
+ }
OS << "\n";
}
@@ -239,6 +267,11 @@ private:
uint64_t CodeAlignmentFactor;
int64_t DataAlignmentFactor;
uint64_t ReturnAddressRegister;
+
+ // The following are used when the CIE represents an EH frame entry.
+ SmallString<8> AugmentationData;
+ uint32_t FDEPointerEncoding;
+ uint32_t LSDAPointerEncoding;
};
@@ -423,7 +456,7 @@ void FrameEntry::dumpInstructions(raw_ostream &OS) const {
}
}
-DWARFDebugFrame::DWARFDebugFrame() {
+DWARFDebugFrame::DWARFDebugFrame(bool IsEH) : IsEH(IsEH) {
}
DWARFDebugFrame::~DWARFDebugFrame() {
@@ -439,6 +472,39 @@ static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
errs() << "\n";
}
+static unsigned getSizeForEncoding(const DataExtractor &Data,
+ unsigned symbolEncoding) {
+ unsigned format = symbolEncoding & 0x0f;
+ switch (format) {
+ default: llvm_unreachable("Unknown Encoding");
+ case dwarf::DW_EH_PE_absptr:
+ case dwarf::DW_EH_PE_signed:
+ return Data.getAddressSize();
+ case dwarf::DW_EH_PE_udata2:
+ case dwarf::DW_EH_PE_sdata2:
+ return 2;
+ case dwarf::DW_EH_PE_udata4:
+ case dwarf::DW_EH_PE_sdata4:
+ return 4;
+ case dwarf::DW_EH_PE_udata8:
+ case dwarf::DW_EH_PE_sdata8:
+ return 8;
+ }
+}
+
+static uint64_t readPointer(const DataExtractor &Data, uint32_t &Offset,
+ unsigned Encoding) {
+ switch (getSizeForEncoding(Data, Encoding)) {
+ case 2:
+ return Data.getU16(&Offset);
+ case 4:
+ return Data.getU32(&Offset);
+ case 8:
+ return Data.getU64(&Offset);
+ default:
+ llvm_unreachable("Illegal data size");
+ }
+}
void DWARFDebugFrame::parse(DataExtractor Data) {
uint32_t Offset = 0;
@@ -447,6 +513,14 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
while (Data.isValidOffset(Offset)) {
uint32_t StartOffset = Offset;
+ auto ReportError = [StartOffset](const char *ErrorMsg) {
+ std::string Str;
+ raw_string_ostream OS(Str);
+ OS << format(ErrorMsg, StartOffset);
+ OS.flush();
+ report_fatal_error(Str);
+ };
+
bool IsDWARF64 = false;
uint64_t Length = Data.getU32(&Offset);
uint64_t Id;
@@ -465,47 +539,132 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
// read).
// TODO: For honest DWARF64 support, DataExtractor will have to treat
// offset_ptr as uint64_t*
+ uint32_t StartStructureOffset = Offset;
uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length);
// The Id field's size depends on the DWARF format
- Id = Data.getUnsigned(&Offset, IsDWARF64 ? 8 : 4);
- bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID);
+ Id = Data.getUnsigned(&Offset, (IsDWARF64 && !IsEH) ? 8 : 4);
+ bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) ||
+ Id == DW_CIE_ID ||
+ (IsEH && !Id));
if (IsCIE) {
uint8_t Version = Data.getU8(&Offset);
const char *Augmentation = Data.getCStr(&Offset);
- uint8_t AddressSize = Version < 4 ? Data.getAddressSize() : Data.getU8(&Offset);
+ StringRef AugmentationString(Augmentation ? Augmentation : "");
+ uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :
+ Data.getU8(&Offset);
Data.setAddressSize(AddressSize);
uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset);
uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
uint64_t ReturnAddressRegister = Data.getULEB128(&Offset);
+ // Parse the augmentation data for EH CIEs
+ StringRef AugmentationData("");
+ uint32_t FDEPointerEncoding = DW_EH_PE_omit;
+ uint32_t LSDAPointerEncoding = DW_EH_PE_omit;
+ if (IsEH) {
+ Optional<uint32_t> PersonalityEncoding;
+ Optional<uint64_t> Personality;
+
+ Optional<uint64_t> AugmentationLength;
+ uint32_t StartAugmentationOffset;
+ uint32_t EndAugmentationOffset;
+
+ // Walk the augmentation string to get all the augmentation data.
+ for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
+ switch (AugmentationString[i]) {
+ default:
+ ReportError("Unknown augmentation character in entry at %lx");
+ case 'L':
+ LSDAPointerEncoding = Data.getU8(&Offset);
+ break;
+ case 'P': {
+ if (Personality)
+ ReportError("Duplicate personality in entry at %lx");
+ PersonalityEncoding = Data.getU8(&Offset);
+ Personality = readPointer(Data, Offset, *PersonalityEncoding);
+ break;
+ }
+ case 'R':
+ FDEPointerEncoding = Data.getU8(&Offset);
+ break;
+ case 'z':
+ if (i)
+ ReportError("'z' must be the first character at %lx");
+ // Parse the augmentation length first. We only parse it if
+ // the string contains a 'z'.
+ AugmentationLength = Data.getULEB128(&Offset);
+ StartAugmentationOffset = Offset;
+ EndAugmentationOffset = Offset +
+ static_cast<uint32_t>(*AugmentationLength);
+ }
+ }
+
+ if (AugmentationLength.hasValue()) {
+ if (Offset != EndAugmentationOffset)
+ ReportError("Parsing augmentation data at %lx failed");
+
+ AugmentationData = Data.getData().slice(StartAugmentationOffset,
+ EndAugmentationOffset);
+ }
+ }
+
auto Cie = make_unique<CIE>(StartOffset, Length, Version,
- StringRef(Augmentation), AddressSize,
+ AugmentationString, AddressSize,
SegmentDescriptorSize, CodeAlignmentFactor,
- DataAlignmentFactor, ReturnAddressRegister);
+ DataAlignmentFactor, ReturnAddressRegister,
+ AugmentationData, FDEPointerEncoding,
+ LSDAPointerEncoding);
CIEs[StartOffset] = Cie.get();
Entries.emplace_back(std::move(Cie));
} else {
// FDE
uint64_t CIEPointer = Id;
- uint64_t InitialLocation = Data.getAddress(&Offset);
- uint64_t AddressRange = Data.getAddress(&Offset);
+ uint64_t InitialLocation = 0;
+ uint64_t AddressRange = 0;
+ CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer];
+
+ if (IsEH) {
+ // The address size is encoded in the CIE we reference.
+ if (!Cie)
+ ReportError("Parsing FDE data at %lx failed due to missing CIE");
+
+ InitialLocation = readPointer(Data, Offset,
+ Cie->getFDEPointerEncoding());
+ AddressRange = readPointer(Data, Offset,
+ Cie->getFDEPointerEncoding());
+
+ StringRef AugmentationString = Cie->getAugmentationString();
+ if (!AugmentationString.empty()) {
+ // Parse the augmentation length and data for this FDE.
+ uint64_t AugmentationLength = Data.getULEB128(&Offset);
+
+ uint32_t EndAugmentationOffset =
+ Offset + static_cast<uint32_t>(AugmentationLength);
+
+ // Decode the LSDA if the CIE augmentation string said we should.
+ if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit)
+ readPointer(Data, Offset, Cie->getLSDAPointerEncoding());
+
+ if (Offset != EndAugmentationOffset)
+ ReportError("Parsing augmentation data at %lx failed");
+ }
+ } else {
+ InitialLocation = Data.getAddress(&Offset);
+ AddressRange = Data.getAddress(&Offset);
+ }
Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer,
InitialLocation, AddressRange,
- CIEs[CIEPointer]));
+ Cie));
}
Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset);
- if (Offset != EndStructureOffset) {
- std::string Str;
- raw_string_ostream OS(Str);
- OS << format("Parsing entry instructions at %lx failed", StartOffset);
- report_fatal_error(Str);
- }
+ if (Offset != EndStructureOffset)
+ ReportError("Parsing entry instructions at %lx failed");
}
}
diff --git a/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index a0bee0da1765..30cb83398dd4 100644
--- a/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -17,9 +17,7 @@ using namespace llvm;
using namespace dwarf;
typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind;
-DWARFDebugLine::Prologue::Prologue() {
- clear();
-}
+DWARFDebugLine::Prologue::Prologue() { clear(); }
void DWARFDebugLine::Prologue::clear() {
TotalLength = Version = PrologueLength = 0;
@@ -44,12 +42,12 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const {
<< format(" opcode_base: %u\n", OpcodeBase);
for (uint32_t i = 0; i < StandardOpcodeLengths.size(); ++i)
- OS << format("standard_opcode_lengths[%s] = %u\n", LNStandardString(i+1),
+ OS << format("standard_opcode_lengths[%s] = %u\n", LNStandardString(i + 1),
StandardOpcodeLengths[i]);
if (!IncludeDirectories.empty())
for (uint32_t i = 0; i < IncludeDirectories.size(); ++i)
- OS << format("include_directories[%3u] = '", i+1)
+ OS << format("include_directories[%3u] = '", i + 1)
<< IncludeDirectories[i] << "'\n";
if (!FileNames.empty()) {
@@ -57,10 +55,10 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const {
<< " ---- ---------- ---------- -----------"
"----------------\n";
for (uint32_t i = 0; i < FileNames.size(); ++i) {
- const FileNameEntry& fileEntry = FileNames[i];
- OS << format("file_names[%3u] %4" PRIu64 " ", i+1, fileEntry.DirIdx)
- << format("0x%8.8" PRIx64 " 0x%8.8" PRIx64 " ",
- fileEntry.ModTime, fileEntry.Length)
+ const FileNameEntry &fileEntry = FileNames[i];
+ OS << format("file_names[%3u] %4" PRIu64 " ", i + 1, fileEntry.DirIdx)
+ << format("0x%8.8" PRIx64 " 0x%8.8" PRIx64 " ", fileEntry.ModTime,
+ fileEntry.Length)
<< fileEntry.Name << '\n';
}
}
@@ -82,8 +80,8 @@ bool DWARFDebugLine::Prologue::parse(DataExtractor debug_line_data,
if (Version < 2)
return false;
- PrologueLength = debug_line_data.getUnsigned(offset_ptr,
- sizeofPrologueLength());
+ PrologueLength =
+ debug_line_data.getUnsigned(offset_ptr, sizeofPrologueLength());
const uint64_t end_prologue_offset = PrologueLength + *offset_ptr;
MinInstLength = debug_line_data.getU8(offset_ptr);
if (Version >= 4)
@@ -131,9 +129,7 @@ bool DWARFDebugLine::Prologue::parse(DataExtractor debug_line_data,
return true;
}
-DWARFDebugLine::Row::Row(bool default_is_stmt) {
- reset(default_is_stmt);
-}
+DWARFDebugLine::Row::Row(bool default_is_stmt) { reset(default_is_stmt); }
void DWARFDebugLine::Row::postAppend() {
BasicBlock = false;
@@ -158,17 +154,13 @@ void DWARFDebugLine::Row::reset(bool default_is_stmt) {
void DWARFDebugLine::Row::dump(raw_ostream &OS) const {
OS << format("0x%16.16" PRIx64 " %6u %6u", Address, Line, Column)
<< format(" %6u %3u %13u ", File, Isa, Discriminator)
- << (IsStmt ? " is_stmt" : "")
- << (BasicBlock ? " basic_block" : "")
+ << (IsStmt ? " is_stmt" : "") << (BasicBlock ? " basic_block" : "")
<< (PrologueEnd ? " prologue_end" : "")
<< (EpilogueBegin ? " epilogue_begin" : "")
- << (EndSequence ? " end_sequence" : "")
- << '\n';
+ << (EndSequence ? " end_sequence" : "") << '\n';
}
-DWARFDebugLine::Sequence::Sequence() {
- reset();
-}
+DWARFDebugLine::Sequence::Sequence() { reset(); }
void DWARFDebugLine::Sequence::reset() {
LowPC = 0;
@@ -178,9 +170,7 @@ void DWARFDebugLine::Sequence::reset() {
Empty = true;
}
-DWARFDebugLine::LineTable::LineTable() {
- clear();
-}
+DWARFDebugLine::LineTable::LineTable() { clear(); }
void DWARFDebugLine::LineTable::dump(raw_ostream &OS) const {
Prologue.dump(OS);
@@ -244,7 +234,7 @@ const DWARFDebugLine::LineTable *
DWARFDebugLine::getOrParseLineTable(DataExtractor debug_line_data,
uint32_t offset) {
std::pair<LineTableIter, bool> pos =
- LineTableMap.insert(LineTableMapTy::value_type(offset, LineTable()));
+ LineTableMap.insert(LineTableMapTy::value_type(offset, LineTable()));
LineTable *LT = &pos.first->second;
if (pos.second) {
if (!LT->parse(debug_line_data, RelocMap, &offset))
@@ -266,8 +256,8 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data,
return false;
}
- const uint32_t end_offset = debug_line_offset + Prologue.TotalLength +
- Prologue.sizeofTotalLength();
+ const uint32_t end_offset =
+ debug_line_offset + Prologue.TotalLength + Prologue.sizeofTotalLength();
ParsingState State(this);
@@ -307,9 +297,9 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data,
// If this address is in our relocation map, apply the relocation.
RelocAddrMap::const_iterator AI = RMap->find(*offset_ptr);
if (AI != RMap->end()) {
- const std::pair<uint8_t, int64_t> &R = AI->second;
- State.Row.Address =
- debug_line_data.getAddress(offset_ptr) + R.second;
+ const std::pair<uint8_t, int64_t> &R = AI->second;
+ State.Row.Address =
+ debug_line_data.getAddress(offset_ptr) + R.second;
} else
State.Row.Address = debug_line_data.getAddress(offset_ptr);
}
@@ -509,6 +499,8 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data,
State.Row.Line += line_offset;
State.Row.Address += addr_offset;
State.appendRowToMatrix(*offset_ptr);
+ // Reset discriminator to 0.
+ State.Row.Discriminator = 0;
}
}
@@ -566,8 +558,8 @@ uint32_t DWARFDebugLine::LineTable::lookupAddress(uint64_t address) const {
sequence.LowPC = address;
SequenceIter first_seq = Sequences.begin();
SequenceIter last_seq = Sequences.end();
- SequenceIter seq_pos = std::lower_bound(first_seq, last_seq, sequence,
- DWARFDebugLine::Sequence::orderByLowPC);
+ SequenceIter seq_pos = std::lower_bound(
+ first_seq, last_seq, sequence, DWARFDebugLine::Sequence::orderByLowPC);
DWARFDebugLine::Sequence found_seq;
if (seq_pos == last_seq) {
found_seq = Sequences.back();
@@ -591,8 +583,8 @@ bool DWARFDebugLine::LineTable::lookupAddressRange(
sequence.LowPC = address;
SequenceIter first_seq = Sequences.begin();
SequenceIter last_seq = Sequences.end();
- SequenceIter seq_pos = std::lower_bound(first_seq, last_seq, sequence,
- DWARFDebugLine::Sequence::orderByLowPC);
+ SequenceIter seq_pos = std::lower_bound(
+ first_seq, last_seq, sequence, DWARFDebugLine::Sequence::orderByLowPC);
if (seq_pos == last_seq || seq_pos->LowPC != address) {
if (seq_pos == first_seq)
return false;
@@ -632,11 +624,10 @@ bool DWARFDebugLine::LineTable::lookupAddressRange(
return true;
}
-bool
-DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex,
- const char *CompDir,
- FileLineInfoKind Kind,
- std::string &Result) const {
+bool DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex,
+ const char *CompDir,
+ FileLineInfoKind Kind,
+ std::string &Result) const {
if (FileIndex == 0 || FileIndex > Prologue.FileNames.size() ||
Kind == FileLineInfoKind::None)
return false;
@@ -669,11 +660,9 @@ DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex,
return true;
}
-bool
-DWARFDebugLine::LineTable::getFileLineInfoForAddress(uint64_t Address,
- const char *CompDir,
- FileLineInfoKind Kind,
- DILineInfo &Result) const {
+bool DWARFDebugLine::LineTable::getFileLineInfoForAddress(
+ uint64_t Address, const char *CompDir, FileLineInfoKind Kind,
+ DILineInfo &Result) const {
// Get the index of row we're looking for in the line table.
uint32_t RowIndex = lookupAddress(Address);
if (RowIndex == -1U)
diff --git a/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
index cd6fbefd05dd..a7b46b842fee 100644
--- a/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp b/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp
index b6555fa6272e..375ff7c99a04 100644
--- a/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp
@@ -7,9 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#include "SyntaxHighlighting.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
-#include "llvm/Support/Compiler.h"
+#include "SyntaxHighlighting.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/DebugInfo/DWARF/DWARFUnit.cpp b/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 92ca2d4c3ff0..13c2b508bfa3 100644
--- a/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -20,7 +20,7 @@ using namespace dwarf;
void DWARFUnitSectionBase::parse(DWARFContext &C, const DWARFSection &Section) {
parseImpl(C, Section, C.getDebugAbbrev(), C.getRangeSection(),
C.getStringSection(), StringRef(), C.getAddrSection(),
- C.getLineSection().Data, C.isLittleEndian());
+ C.getLineSection().Data, C.isLittleEndian(), false);
}
void DWARFUnitSectionBase::parseDWO(DWARFContext &C,
@@ -28,13 +28,14 @@ void DWARFUnitSectionBase::parseDWO(DWARFContext &C,
DWARFUnitIndex *Index) {
parseImpl(C, DWOSection, C.getDebugAbbrevDWO(), C.getRangeDWOSection(),
C.getStringDWOSection(), C.getStringOffsetDWOSection(),
- C.getAddrSection(), C.getLineDWOSection().Data, C.isLittleEndian());
+ C.getAddrSection(), C.getLineDWOSection().Data, C.isLittleEndian(),
+ true);
}
DWARFUnit::DWARFUnit(DWARFContext &DC, 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 *IndexEntry)
: Context(DC), InfoSection(Section), Abbrev(DA), RangeSection(RS),
LineSection(LS), StringSection(SS), StringOffsetSection([&]() {
@@ -43,8 +44,8 @@ DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section,
return SOS.slice(C->Offset, C->Offset + C->Length);
return SOS;
}()),
- AddrOffsetSection(AOS), isLittleEndian(LE), UnitSection(UnitSection),
- IndexEntry(IndexEntry) {
+ AddrOffsetSection(AOS), isLittleEndian(LE), isDWO(IsDWO),
+ UnitSection(UnitSection), IndexEntry(IndexEntry) {
clear();
}
@@ -268,8 +269,11 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
DWARFUnit::DWOHolder::DWOHolder(StringRef DWOPath)
: DWOFile(), DWOContext(), DWOU(nullptr) {
auto Obj = object::ObjectFile::createObjectFile(DWOPath);
- if (!Obj)
+ if (!Obj) {
+ // TODO: Actually report errors helpfully.
+ consumeError(Obj.takeError());
return;
+ }
DWOFile = std::move(Obj.get());
DWOContext.reset(
cast<DWARFContext>(new DWARFContextInMemory(*DWOFile.getBinary())));
@@ -278,6 +282,8 @@ DWARFUnit::DWOHolder::DWOHolder(StringRef DWOPath)
}
bool DWARFUnit::parseDWO() {
+ if (isDWO)
+ return false;
if (DWO.get())
return false;
extractDIEsIfNeeded(true);
@@ -375,19 +381,14 @@ DWARFUnit::getInlinedChainForAddress(uint64_t Address) {
// First, find a subprogram that contains the given address (the root
// of inlined chain).
const DWARFUnit *ChainCU = nullptr;
- const DWARFDebugInfoEntryMinimal *SubprogramDIE =
- getSubprogramForAddress(Address);
- if (SubprogramDIE) {
+ const DWARFDebugInfoEntryMinimal *SubprogramDIE;
+ // Try to look for subprogram DIEs in the DWO file.
+ parseDWO();
+ if (DWO) {
+ if ((SubprogramDIE = DWO->getUnit()->getSubprogramForAddress(Address)))
+ ChainCU = DWO->getUnit();
+ } else if ((SubprogramDIE = getSubprogramForAddress(Address)))
ChainCU = this;
- } else {
- // Try to look for subprogram DIEs in the DWO file.
- parseDWO();
- if (DWO.get()) {
- SubprogramDIE = DWO->getUnit()->getSubprogramForAddress(Address);
- if (SubprogramDIE)
- ChainCU = DWO->getUnit();
- }
- }
// Get inlined chain rooted at this subprogram DIE.
if (!SubprogramDIE)
diff --git a/lib/DebugInfo/DWARF/Makefile b/lib/DebugInfo/DWARF/Makefile
deleted file mode 100644
index 863337353d0a..000000000000
--- a/lib/DebugInfo/DWARF/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-##===- lib/DebugInfo/DWARF/Makefile ------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../../..
-LIBRARYNAME = LLVMDebugInfoDWARF
-BUILD_ARCHIVE := 1
-
-include $(LEVEL)/Makefile.common
diff --git a/lib/DebugInfo/DWARF/module.modulemap b/lib/DebugInfo/DWARF/module.modulemap
deleted file mode 100644
index c2f624fd4b6c..000000000000
--- a/lib/DebugInfo/DWARF/module.modulemap
+++ /dev/null
@@ -1 +0,0 @@
-module DebugInfoDWARF { requires cplusplus umbrella "." module * { export * } }
diff --git a/lib/DebugInfo/Makefile b/lib/DebugInfo/Makefile
deleted file mode 100644
index 6072af314416..000000000000
--- a/lib/DebugInfo/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-##===- lib/DebugInfo/Makefile ------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-LEVEL = ../..
-
-include $(LEVEL)/Makefile.config
-
-PARALLEL_DIRS := CodeView DWARF PDB Symbolize
-
-include $(LEVEL)/Makefile.common
diff --git a/lib/DebugInfo/PDB/CMakeLists.txt b/lib/DebugInfo/PDB/CMakeLists.txt
index 1645a95aac36..b5a2bc1600fc 100644
--- a/lib/DebugInfo/PDB/CMakeLists.txt
+++ b/lib/DebugInfo/PDB/CMakeLists.txt
@@ -17,6 +17,7 @@ if(HAVE_DIA_SDK)
DIA/DIAEnumLineNumbers.cpp
DIA/DIAEnumSourceFiles.cpp
DIA/DIAEnumSymbols.cpp
+ DIA/DIAError.cpp
DIA/DIALineNumber.cpp
DIA/DIARawSymbol.cpp
DIA/DIASession.cpp
@@ -24,12 +25,37 @@ if(HAVE_DIA_SDK)
)
set(LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB/DIA")
-
endif()
+add_pdb_impl_folder(Raw
+ Raw/DbiStream.cpp
+ Raw/DbiStreamBuilder.cpp
+ Raw/EnumTables.cpp
+ Raw/Hash.cpp
+ Raw/IndexedStreamData.cpp
+ Raw/InfoStream.cpp
+ Raw/InfoStreamBuilder.cpp
+ Raw/MappedBlockStream.cpp
+ Raw/ModInfo.cpp
+ Raw/ModStream.cpp
+ Raw/MsfBuilder.cpp
+ Raw/MsfCommon.cpp
+ Raw/NameHashTable.cpp
+ Raw/NameMap.cpp
+ Raw/NameMapBuilder.cpp
+ Raw/PDBFile.cpp
+ Raw/PDBFileBuilder.cpp
+ Raw/PublicsStream.cpp
+ Raw/RawError.cpp
+ Raw/RawSession.cpp
+ Raw/SymbolStream.cpp
+ Raw/TpiStream.cpp)
+
+list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB/Raw")
list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB")
add_llvm_library(LLVMDebugInfoPDB
+ GenericError.cpp
IPDBSourceFile.cpp
PDB.cpp
PDBContext.cpp
diff --git a/lib/DebugInfo/PDB/DIA/DIADataStream.cpp b/lib/DebugInfo/PDB/DIA/DIADataStream.cpp
index e0e1b2712467..7eabed8cad48 100644
--- a/lib/DebugInfo/PDB/DIA/DIADataStream.cpp
+++ b/lib/DebugInfo/PDB/DIA/DIADataStream.cpp
@@ -8,9 +8,11 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/PDB/DIA/DIADataStream.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/ConvertUTF.h"
using namespace llvm;
+using namespace llvm::pdb;
DIADataStream::DIADataStream(CComPtr<IDiaEnumDebugStreamData> DiaStreamData)
: StreamData(DiaStreamData) {}
diff --git a/lib/DebugInfo/PDB/DIA/DIAEnumDebugStreams.cpp b/lib/DebugInfo/PDB/DIA/DIAEnumDebugStreams.cpp
index 23c6489c7e18..cae817c1b367 100644
--- a/lib/DebugInfo/PDB/DIA/DIAEnumDebugStreams.cpp
+++ b/lib/DebugInfo/PDB/DIA/DIAEnumDebugStreams.cpp
@@ -12,6 +12,7 @@
#include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h"
using namespace llvm;
+using namespace llvm::pdb;
DIAEnumDebugStreams::DIAEnumDebugStreams(
CComPtr<IDiaEnumDebugStreams> DiaEnumerator)
diff --git a/lib/DebugInfo/PDB/DIA/DIAEnumLineNumbers.cpp b/lib/DebugInfo/PDB/DIA/DIAEnumLineNumbers.cpp
index 32a9af214dc0..4741d9c9a849 100644
--- a/lib/DebugInfo/PDB/DIA/DIAEnumLineNumbers.cpp
+++ b/lib/DebugInfo/PDB/DIA/DIAEnumLineNumbers.cpp
@@ -12,6 +12,7 @@
#include "llvm/DebugInfo/PDB/DIA/DIALineNumber.h"
using namespace llvm;
+using namespace llvm::pdb;
DIAEnumLineNumbers::DIAEnumLineNumbers(
CComPtr<IDiaEnumLineNumbers> DiaEnumerator)
diff --git a/lib/DebugInfo/PDB/DIA/DIAEnumSourceFiles.cpp b/lib/DebugInfo/PDB/DIA/DIAEnumSourceFiles.cpp
index 1a946100fef2..ccf8c4e622cc 100644
--- a/lib/DebugInfo/PDB/DIA/DIAEnumSourceFiles.cpp
+++ b/lib/DebugInfo/PDB/DIA/DIAEnumSourceFiles.cpp
@@ -12,6 +12,7 @@
#include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h"
using namespace llvm;
+using namespace llvm::pdb;
DIAEnumSourceFiles::DIAEnumSourceFiles(
const DIASession &PDBSession, CComPtr<IDiaEnumSourceFiles> DiaEnumerator)
diff --git a/lib/DebugInfo/PDB/DIA/DIAEnumSymbols.cpp b/lib/DebugInfo/PDB/DIA/DIAEnumSymbols.cpp
index 6754d9a97d70..3c211b569044 100644
--- a/lib/DebugInfo/PDB/DIA/DIAEnumSymbols.cpp
+++ b/lib/DebugInfo/PDB/DIA/DIAEnumSymbols.cpp
@@ -13,6 +13,7 @@
#include "llvm/DebugInfo/PDB/DIA/DIASession.h"
using namespace llvm;
+using namespace llvm::pdb;
DIAEnumSymbols::DIAEnumSymbols(const DIASession &PDBSession,
CComPtr<IDiaEnumSymbols> DiaEnumerator)
diff --git a/lib/DebugInfo/PDB/DIA/DIAError.cpp b/lib/DebugInfo/PDB/DIA/DIAError.cpp
new file mode 100644
index 000000000000..1d72a92b5145
--- /dev/null
+++ b/lib/DebugInfo/PDB/DIA/DIAError.cpp
@@ -0,0 +1,59 @@
+#include "llvm/DebugInfo/PDB/DIA/DIAError.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+// FIXME: This class is only here to support the transition to llvm::Error. It
+// will be removed once this transition is complete. Clients should prefer to
+// deal with the Error value directly, rather than converting to error_code.
+class DIAErrorCategory : public std::error_category {
+public:
+ const char *name() const LLVM_NOEXCEPT override { return "llvm.pdb.dia"; }
+
+ std::string message(int Condition) const override {
+ switch (static_cast<dia_error_code>(Condition)) {
+ case dia_error_code::could_not_create_impl:
+ return "Failed to connect to DIA at runtime. Verify that Visual Studio "
+ "is properly installed, or that msdiaXX.dll is in your PATH.";
+ case dia_error_code::invalid_file_format:
+ return "Unable to load PDB. The file has an unrecognized format.";
+ case dia_error_code::invalid_parameter:
+ return "The parameter is incorrect.";
+ case dia_error_code::already_loaded:
+ return "Unable to load the PDB or EXE, because it is already loaded.";
+ case dia_error_code::debug_info_mismatch:
+ return "The PDB file and the EXE file do not match.";
+ case dia_error_code::unspecified:
+ return "An unknown error has occurred.";
+ }
+ llvm_unreachable("Unrecognized DIAErrorCode");
+ }
+};
+
+static ManagedStatic<DIAErrorCategory> Category;
+
+char DIAError::ID = 0;
+
+DIAError::DIAError(dia_error_code C) : DIAError(C, "") {}
+
+DIAError::DIAError(const std::string &Context)
+ : DIAError(dia_error_code::unspecified, Context) {}
+
+DIAError::DIAError(dia_error_code C, const std::string &Context) : Code(C) {
+ ErrMsg = "DIA Error: ";
+ std::error_code EC = convertToErrorCode();
+ if (Code != dia_error_code::unspecified)
+ ErrMsg += EC.message() + " ";
+ if (!Context.empty())
+ ErrMsg += Context;
+}
+
+void DIAError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; }
+
+const std::string &DIAError::getErrorMessage() const { return ErrMsg; }
+
+std::error_code DIAError::convertToErrorCode() const {
+ return std::error_code(static_cast<int>(Code), *Category);
+}
diff --git a/lib/DebugInfo/PDB/DIA/DIALineNumber.cpp b/lib/DebugInfo/PDB/DIA/DIALineNumber.cpp
index c5577f15eb8e..b19be6b595ab 100644
--- a/lib/DebugInfo/PDB/DIA/DIALineNumber.cpp
+++ b/lib/DebugInfo/PDB/DIA/DIALineNumber.cpp
@@ -10,6 +10,7 @@
#include "llvm/DebugInfo/PDB/DIA/DIALineNumber.h"
using namespace llvm;
+using namespace llvm::pdb;
DIALineNumber::DIALineNumber(CComPtr<IDiaLineNumber> DiaLineNumber)
: LineNumber(DiaLineNumber) {}
diff --git a/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp b/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp
index abe0ab55e56c..bba5b0f94dca 100644
--- a/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp
+++ b/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp
@@ -7,64 +7,77 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h"
-#include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h"
#include "llvm/DebugInfo/PDB/DIA/DIASession.h"
#include "llvm/DebugInfo/PDB/PDBExtras.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
+using namespace llvm::pdb;
namespace {
Variant VariantFromVARIANT(const VARIANT &V) {
Variant Result;
switch (V.vt) {
case VT_I1:
- Result.Int8 = V.cVal;
+ Result.Value.Int8 = V.cVal;
Result.Type = PDB_VariantType::Int8;
break;
case VT_I2:
- Result.Int16 = V.iVal;
+ Result.Value.Int16 = V.iVal;
Result.Type = PDB_VariantType::Int16;
break;
case VT_I4:
- Result.Int32 = V.intVal;
+ Result.Value.Int32 = V.intVal;
Result.Type = PDB_VariantType::Int32;
break;
case VT_I8:
- Result.Int64 = V.llVal;
+ Result.Value.Int64 = V.llVal;
Result.Type = PDB_VariantType::Int64;
break;
case VT_UI1:
- Result.UInt8 = V.bVal;
+ Result.Value.UInt8 = V.bVal;
Result.Type = PDB_VariantType::UInt8;
break;
case VT_UI2:
- Result.UInt16 = V.uiVal;
+ Result.Value.UInt16 = V.uiVal;
Result.Type = PDB_VariantType::UInt16;
break;
case VT_UI4:
- Result.UInt32 = V.uintVal;
+ Result.Value.UInt32 = V.uintVal;
Result.Type = PDB_VariantType::UInt32;
break;
case VT_UI8:
- Result.UInt64 = V.ullVal;
+ Result.Value.UInt64 = V.ullVal;
Result.Type = PDB_VariantType::UInt64;
break;
case VT_BOOL:
- Result.Bool = (V.boolVal == VARIANT_TRUE) ? true : false;
+ Result.Value.Bool = (V.boolVal == VARIANT_TRUE) ? true : false;
Result.Type = PDB_VariantType::Bool;
break;
case VT_R4:
- Result.Single = V.fltVal;
+ Result.Value.Single = V.fltVal;
Result.Type = PDB_VariantType::Single;
break;
case VT_R8:
- Result.Double = V.dblVal;
+ Result.Value.Double = V.dblVal;
Result.Type = PDB_VariantType::Double;
break;
+ case VT_BSTR: {
+ const char *SrcBytes = reinterpret_cast<const char *>(V.bstrVal);
+ llvm::ArrayRef<char> SrcByteArray(SrcBytes, SysStringByteLen(V.bstrVal));
+ std::string Result8;
+ if (!llvm::convertUTF16ToUTF8String(SrcByteArray, Result8))
+ Result.Value.String = nullptr;
+ Result.Value.String = new char[Result8.length() + 1];
+ ::strcpy(Result.Value.String, Result8.c_str());
+ Result.Type = PDB_VariantType::String;
+ break;
+ }
default:
Result.Type = PDB_VariantType::Unknown;
break;
@@ -521,8 +534,8 @@ uint32_t DIARawSymbol::getLiveRangeStartRelativeVirtualAddress() const {
Symbol, &IDiaSymbol::get_liveRangeStartRelativeVirtualAddress);
}
-PDB_RegisterId DIARawSymbol::getLocalBasePointerRegisterId() const {
- return PrivateGetDIAValue<DWORD, PDB_RegisterId>(
+codeview::RegisterId DIARawSymbol::getLocalBasePointerRegisterId() const {
+ return PrivateGetDIAValue<DWORD, codeview::RegisterId>(
Symbol, &IDiaSymbol::get_localBasePointerRegisterId);
}
@@ -583,9 +596,9 @@ uint32_t DIARawSymbol::getRank() const {
return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_rank);
}
-PDB_RegisterId DIARawSymbol::getRegisterId() const {
- return PrivateGetDIAValue<DWORD, PDB_RegisterId>(Symbol,
- &IDiaSymbol::get_registerId);
+codeview::RegisterId DIARawSymbol::getRegisterId() const {
+ return PrivateGetDIAValue<DWORD, codeview::RegisterId>(
+ Symbol, &IDiaSymbol::get_registerId);
}
uint32_t DIARawSymbol::getRegisterType() const {
@@ -738,8 +751,8 @@ PDB_Machine DIARawSymbol::getMachineType() const {
&IDiaSymbol::get_machineType);
}
-PDB_ThunkOrdinal DIARawSymbol::getThunkOrdinal() const {
- return PrivateGetDIAValue<DWORD, PDB_ThunkOrdinal>(
+codeview::ThunkOrdinal DIARawSymbol::getThunkOrdinal() const {
+ return PrivateGetDIAValue<DWORD, codeview::ThunkOrdinal>(
Symbol, &IDiaSymbol::get_thunkOrdinal);
}
diff --git a/lib/DebugInfo/PDB/DIA/DIASession.cpp b/lib/DebugInfo/PDB/DIA/DIASession.cpp
index 99fe750ebac6..fa224af8cb87 100644
--- a/lib/DebugInfo/PDB/DIA/DIASession.cpp
+++ b/lib/DebugInfo/PDB/DIA/DIASession.cpp
@@ -6,107 +6,125 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-
+#include "llvm/DebugInfo/PDB/DIA/DIASession.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h"
#include "llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h"
#include "llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h"
+#include "llvm/DebugInfo/PDB/DIA/DIAError.h"
#include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h"
-#include "llvm/DebugInfo/PDB/DIA/DIASession.h"
#include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h"
+#include "llvm/DebugInfo/PDB/DIA/DIASupport.h"
+#include "llvm/DebugInfo/PDB/GenericError.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
#include "llvm/Support/ConvertUTF.h"
using namespace llvm;
+using namespace llvm::pdb;
+
+namespace {
+
+Error ErrorFromHResult(HRESULT Result) {
+ switch (Result) {
+ case E_PDB_NOT_FOUND:
+ return make_error<GenericError>(generic_error_code::invalid_path);
+ case E_PDB_FORMAT:
+ return make_error<DIAError>(dia_error_code::invalid_file_format);
+ case E_INVALIDARG:
+ return make_error<DIAError>(dia_error_code::invalid_parameter);
+ case E_UNEXPECTED:
+ return make_error<DIAError>(dia_error_code::already_loaded);
+ case E_PDB_INVALID_SIG:
+ case E_PDB_INVALID_AGE:
+ return make_error<DIAError>(dia_error_code::debug_info_mismatch);
+ default:
+ return make_error<DIAError>(dia_error_code::unspecified);
+ }
+}
-namespace {}
+Error LoadDIA(CComPtr<IDiaDataSource> &DiaDataSource) {
+ if (SUCCEEDED(CoCreateInstance(CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER,
+ IID_IDiaDataSource,
+ reinterpret_cast<LPVOID *>(&DiaDataSource))))
+ return Error::success();
+
+// If the CoCreateInstance call above failed, msdia*.dll is not registered.
+// Try loading the DLL corresponding to the #included DIA SDK.
+#if !defined(_MSC_VER)
+ return llvm::make_error<GenericError>(
+ "DIA is only supported when using MSVC.");
+#endif
+
+ const wchar_t *msdia_dll = nullptr;
+#if _MSC_VER == 1900
+ msdia_dll = L"msdia140.dll"; // VS2015
+#elif _MSC_VER == 1800
+ msdia_dll = L"msdia120.dll"; // VS2013
+#else
+#error "Unknown Visual Studio version."
+#endif
+
+ HRESULT HR;
+ if (FAILED(HR = NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource,
+ reinterpret_cast<LPVOID *>(&DiaDataSource))))
+ return ErrorFromHResult(HR);
+ return Error::success();
+}
+
+}
DIASession::DIASession(CComPtr<IDiaSession> DiaSession) : Session(DiaSession) {}
-PDB_ErrorCode DIASession::createFromPdb(StringRef Path,
- std::unique_ptr<IPDBSession> &Session) {
+Error DIASession::createFromPdb(StringRef Path,
+ std::unique_ptr<IPDBSession> &Session) {
CComPtr<IDiaDataSource> DiaDataSource;
CComPtr<IDiaSession> DiaSession;
// We assume that CoInitializeEx has already been called by the executable.
- HRESULT Result = ::CoCreateInstance(
- CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER, IID_IDiaDataSource,
- reinterpret_cast<LPVOID *>(&DiaDataSource));
- if (FAILED(Result))
- return PDB_ErrorCode::NoPdbImpl;
+ if (auto E = LoadDIA(DiaDataSource))
+ return E;
llvm::SmallVector<UTF16, 128> Path16;
if (!llvm::convertUTF8ToUTF16String(Path, Path16))
- return PDB_ErrorCode::InvalidPath;
+ return make_error<GenericError>(generic_error_code::invalid_path);
const wchar_t *Path16Str = reinterpret_cast<const wchar_t*>(Path16.data());
- if (FAILED(Result = DiaDataSource->loadDataFromPdb(Path16Str))) {
- if (Result == E_PDB_NOT_FOUND)
- return PDB_ErrorCode::InvalidPath;
- else if (Result == E_PDB_FORMAT)
- return PDB_ErrorCode::InvalidFileFormat;
- else if (Result == E_INVALIDARG)
- return PDB_ErrorCode::InvalidParameter;
- else if (Result == E_UNEXPECTED)
- return PDB_ErrorCode::AlreadyLoaded;
- else
- return PDB_ErrorCode::UnknownError;
- }
+ HRESULT HR;
+ if (FAILED(HR = DiaDataSource->loadDataFromPdb(Path16Str)))
+ return ErrorFromHResult(HR);
- if (FAILED(Result = DiaDataSource->openSession(&DiaSession))) {
- if (Result == E_OUTOFMEMORY)
- return PDB_ErrorCode::NoMemory;
- else
- return PDB_ErrorCode::UnknownError;
- }
+ if (FAILED(HR = DiaDataSource->openSession(&DiaSession)))
+ return ErrorFromHResult(HR);
Session.reset(new DIASession(DiaSession));
- return PDB_ErrorCode::Success;
+ return Error::success();
}
-PDB_ErrorCode DIASession::createFromExe(StringRef Path,
- std::unique_ptr<IPDBSession> &Session) {
+Error DIASession::createFromExe(StringRef Path,
+ std::unique_ptr<IPDBSession> &Session) {
CComPtr<IDiaDataSource> DiaDataSource;
CComPtr<IDiaSession> DiaSession;
// We assume that CoInitializeEx has already been called by the executable.
- HRESULT Result = ::CoCreateInstance(
- CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER, IID_IDiaDataSource,
- reinterpret_cast<LPVOID *>(&DiaDataSource));
- if (FAILED(Result))
- return PDB_ErrorCode::NoPdbImpl;
+ if (auto EC = LoadDIA(DiaDataSource))
+ return EC;
llvm::SmallVector<UTF16, 128> Path16;
if (!llvm::convertUTF8ToUTF16String(Path, Path16))
- return PDB_ErrorCode::InvalidPath;
+ return make_error<GenericError>(generic_error_code::invalid_path, Path);
const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data());
- if (FAILED(Result =
- DiaDataSource->loadDataForExe(Path16Str, nullptr, nullptr))) {
- if (Result == E_PDB_NOT_FOUND)
- return PDB_ErrorCode::InvalidPath;
- else if (Result == E_PDB_FORMAT)
- return PDB_ErrorCode::InvalidFileFormat;
- else if (Result == E_PDB_INVALID_SIG || Result == E_PDB_INVALID_AGE)
- return PDB_ErrorCode::DebugInfoMismatch;
- else if (Result == E_INVALIDARG)
- return PDB_ErrorCode::InvalidParameter;
- else if (Result == E_UNEXPECTED)
- return PDB_ErrorCode::AlreadyLoaded;
- else
- return PDB_ErrorCode::UnknownError;
- }
+ HRESULT HR;
+ if (FAILED(HR = DiaDataSource->loadDataForExe(Path16Str, nullptr, nullptr)))
+ return ErrorFromHResult(HR);
- if (FAILED(Result = DiaDataSource->openSession(&DiaSession))) {
- if (Result == E_OUTOFMEMORY)
- return PDB_ErrorCode::NoMemory;
- else
- return PDB_ErrorCode::UnknownError;
- }
+ if (FAILED(HR = DiaDataSource->openSession(&DiaSession)))
+ return ErrorFromHResult(HR);
Session.reset(new DIASession(DiaSession));
- return PDB_ErrorCode::Success;
+ return Error::success();
}
uint64_t DIASession::getLoadAddress() const {
@@ -158,6 +176,22 @@ DIASession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) const {
}
std::unique_ptr<IPDBEnumLineNumbers>
+DIASession::findLineNumbers(const PDBSymbolCompiland &Compiland,
+ const IPDBSourceFile &File) const {
+ const DIARawSymbol &RawCompiland =
+ static_cast<const DIARawSymbol &>(Compiland.getRawSymbol());
+ const DIASourceFile &RawFile = static_cast<const DIASourceFile &>(File);
+
+ CComPtr<IDiaEnumLineNumbers> LineNumbers;
+ if (S_OK !=
+ Session->findLines(RawCompiland.getDiaSymbol(), RawFile.getDiaFile(),
+ &LineNumbers))
+ return nullptr;
+
+ return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers);
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
DIASession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const {
CComPtr<IDiaEnumLineNumbers> LineNumbers;
if (S_OK != Session->findLinesByVA(Address, Length, &LineNumbers))
@@ -166,6 +200,56 @@ DIASession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const {
return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers);
}
+std::unique_ptr<IPDBEnumSourceFiles>
+DIASession::findSourceFiles(const PDBSymbolCompiland *Compiland,
+ llvm::StringRef Pattern,
+ PDB_NameSearchFlags Flags) const {
+ IDiaSymbol *DiaCompiland = nullptr;
+ CComBSTR Utf16Pattern;
+ if (!Pattern.empty())
+ Utf16Pattern = CComBSTR(Pattern.data());
+
+ if (Compiland)
+ DiaCompiland = static_cast<const DIARawSymbol &>(Compiland->getRawSymbol())
+ .getDiaSymbol();
+
+ Flags = static_cast<PDB_NameSearchFlags>(
+ Flags | PDB_NameSearchFlags::NS_FileNameExtMatch);
+ CComPtr<IDiaEnumSourceFiles> SourceFiles;
+ if (S_OK !=
+ Session->findFile(DiaCompiland, Utf16Pattern.m_str, Flags, &SourceFiles))
+ return nullptr;
+ return llvm::make_unique<DIAEnumSourceFiles>(*this, SourceFiles);
+}
+
+std::unique_ptr<IPDBSourceFile>
+DIASession::findOneSourceFile(const PDBSymbolCompiland *Compiland,
+ llvm::StringRef Pattern,
+ PDB_NameSearchFlags Flags) const {
+ auto SourceFiles = findSourceFiles(Compiland, Pattern, Flags);
+ if (!SourceFiles || SourceFiles->getChildCount() == 0)
+ return nullptr;
+ return SourceFiles->getNext();
+}
+
+std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
+DIASession::findCompilandsForSourceFile(llvm::StringRef Pattern,
+ PDB_NameSearchFlags Flags) const {
+ auto File = findOneSourceFile(nullptr, Pattern, Flags);
+ if (!File)
+ return nullptr;
+ return File->getCompilands();
+}
+
+std::unique_ptr<PDBSymbolCompiland>
+DIASession::findOneCompilandForSourceFile(llvm::StringRef Pattern,
+ PDB_NameSearchFlags Flags) const {
+ auto Compilands = findCompilandsForSourceFile(Pattern, Flags);
+ if (!Compilands || Compilands->getChildCount() == 0)
+ return nullptr;
+ return Compilands->getNext();
+}
+
std::unique_ptr<IPDBEnumSourceFiles> DIASession::getAllSourceFiles() const {
CComPtr<IDiaEnumSourceFiles> Files;
if (S_OK != Session->findFile(nullptr, nullptr, nsNone, &Files))
diff --git a/lib/DebugInfo/PDB/DIA/DIASourceFile.cpp b/lib/DebugInfo/PDB/DIA/DIASourceFile.cpp
index 0a9c444f5e6e..8605f55b402c 100644
--- a/lib/DebugInfo/PDB/DIA/DIASourceFile.cpp
+++ b/lib/DebugInfo/PDB/DIA/DIASourceFile.cpp
@@ -7,12 +7,16 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h"
#include "llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h"
#include "llvm/DebugInfo/PDB/DIA/DIASession.h"
-#include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
#include "llvm/Support/ConvertUTF.h"
using namespace llvm;
+using namespace llvm::pdb;
DIASourceFile::DIASourceFile(const DIASession &PDBSession,
CComPtr<IDiaSourceFile> DiaSourceFile)
@@ -56,12 +60,15 @@ PDB_Checksum DIASourceFile::getChecksumType() const {
return static_cast<PDB_Checksum>(Type);
}
-std::unique_ptr<IPDBEnumSymbols> DIASourceFile::getCompilands() const {
+std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
+DIASourceFile::getCompilands() const {
CComPtr<IDiaEnumSymbols> DiaEnumerator;
HRESULT Result = SourceFile->get_compilands(&DiaEnumerator);
if (S_OK != Result)
return nullptr;
- return std::unique_ptr<IPDBEnumSymbols>(
+ auto Enumerator = std::unique_ptr<IPDBEnumSymbols>(
new DIAEnumSymbols(Session, DiaEnumerator));
+ return std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>(
+ new ConcreteSymbolEnumerator<PDBSymbolCompiland>(std::move(Enumerator)));
}
diff --git a/lib/DebugInfo/PDB/GenericError.cpp b/lib/DebugInfo/PDB/GenericError.cpp
new file mode 100644
index 000000000000..34e179998021
--- /dev/null
+++ b/lib/DebugInfo/PDB/GenericError.cpp
@@ -0,0 +1,67 @@
+//===- Error.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/GenericError.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+namespace {
+// FIXME: This class is only here to support the transition to llvm::Error. It
+// will be removed once this transition is complete. Clients should prefer to
+// deal with the Error value directly, rather than converting to error_code.
+class GenericErrorCategory : public std::error_category {
+public:
+ const char *name() const LLVM_NOEXCEPT override { return "llvm.pdb"; }
+
+ std::string message(int Condition) const override {
+ switch (static_cast<generic_error_code>(Condition)) {
+ case generic_error_code::unspecified:
+ return "An unknown error has occurred.";
+ case generic_error_code::dia_sdk_not_present:
+ return "LLVM was not compiled with support for DIA. This usually means "
+ "that you are are not using MSVC, or your Visual Studio "
+ "installation "
+ "is corrupt.";
+ case generic_error_code::invalid_path:
+ return "Unable to load PDB. Make sure the file exists and is readable.";
+ }
+ llvm_unreachable("Unrecognized generic_error_code");
+ }
+};
+} // end anonymous namespace
+
+static ManagedStatic<GenericErrorCategory> Category;
+
+char GenericError::ID = 0;
+
+GenericError::GenericError(generic_error_code C) : GenericError(C, "") {}
+
+GenericError::GenericError(const std::string &Context)
+ : GenericError(generic_error_code::unspecified, Context) {}
+
+GenericError::GenericError(generic_error_code C, const std::string &Context)
+ : Code(C) {
+ ErrMsg = "PDB Error: ";
+ std::error_code EC = convertToErrorCode();
+ if (Code != generic_error_code::unspecified)
+ ErrMsg += EC.message() + " ";
+ if (!Context.empty())
+ ErrMsg += Context;
+}
+
+void GenericError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; }
+
+const std::string &GenericError::getErrorMessage() const { return ErrMsg; }
+
+std::error_code GenericError::convertToErrorCode() const {
+ return std::error_code(static_cast<int>(Code), *Category);
+}
diff --git a/lib/DebugInfo/PDB/IPDBSourceFile.cpp b/lib/DebugInfo/PDB/IPDBSourceFile.cpp
index 3abe59dba623..46b422f5a76a 100644
--- a/lib/DebugInfo/PDB/IPDBSourceFile.cpp
+++ b/lib/DebugInfo/PDB/IPDBSourceFile.cpp
@@ -14,6 +14,7 @@
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
+using namespace llvm::pdb;
IPDBSourceFile::~IPDBSourceFile() {}
diff --git a/lib/DebugInfo/PDB/LLVMBuild.txt b/lib/DebugInfo/PDB/LLVMBuild.txt
index 9ee9f4067e99..76e537a57fc1 100644
--- a/lib/DebugInfo/PDB/LLVMBuild.txt
+++ b/lib/DebugInfo/PDB/LLVMBuild.txt
@@ -19,5 +19,5 @@
type = Library
name = DebugInfoPDB
parent = DebugInfo
-required_libraries = Object Support
+required_libraries = Object Support DebugInfoCodeView
diff --git a/lib/DebugInfo/PDB/Makefile b/lib/DebugInfo/PDB/Makefile
deleted file mode 100644
index 444019e5a184..000000000000
--- a/lib/DebugInfo/PDB/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-##===- lib/DebugInfo/PDB/Makefile --------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../../..
-LIBRARYNAME = LLVMDebugInfoPDB
-BUILD_ARCHIVE := 1
-
-include $(LEVEL)/Makefile.common
diff --git a/lib/DebugInfo/PDB/PDB.cpp b/lib/DebugInfo/PDB/PDB.cpp
index 613407eb1346..69a908eb341c 100644
--- a/lib/DebugInfo/PDB/PDB.cpp
+++ b/lib/DebugInfo/PDB/PDB.cpp
@@ -11,29 +11,41 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Config/config.h"
+#include "llvm/DebugInfo/PDB/GenericError.h"
#include "llvm/DebugInfo/PDB/IPDBSession.h"
#include "llvm/DebugInfo/PDB/PDB.h"
-
#if HAVE_DIA_SDK
#include "llvm/DebugInfo/PDB/DIA/DIASession.h"
#endif
+#include "llvm/DebugInfo/PDB/Raw/RawSession.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
using namespace llvm;
+using namespace llvm::pdb;
-PDB_ErrorCode llvm::loadDataForPDB(PDB_ReaderType Type, StringRef Path,
- std::unique_ptr<IPDBSession> &Session) {
+Error llvm::pdb::loadDataForPDB(PDB_ReaderType Type, StringRef Path,
+ std::unique_ptr<IPDBSession> &Session) {
// Create the correct concrete instance type based on the value of Type.
+ if (Type == PDB_ReaderType::Raw)
+ return RawSession::createFromPdb(Path, Session);
+
#if HAVE_DIA_SDK
return DIASession::createFromPdb(Path, Session);
+#else
+ return llvm::make_error<GenericError>("DIA is not installed on the system");
#endif
- return PDB_ErrorCode::NoPdbImpl;
}
-PDB_ErrorCode llvm::loadDataForEXE(PDB_ReaderType Type, StringRef Path,
- std::unique_ptr<IPDBSession> &Session) {
+Error llvm::pdb::loadDataForEXE(PDB_ReaderType Type, StringRef Path,
+ std::unique_ptr<IPDBSession> &Session) {
// Create the correct concrete instance type based on the value of Type.
+ if (Type == PDB_ReaderType::Raw)
+ return RawSession::createFromExe(Path, Session);
+
#if HAVE_DIA_SDK
return DIASession::createFromExe(Path, Session);
+#else
+ return llvm::make_error<GenericError>("DIA is not installed on the system");
#endif
- return PDB_ErrorCode::NoPdbImpl;
}
diff --git a/lib/DebugInfo/PDB/PDBContext.cpp b/lib/DebugInfo/PDB/PDBContext.cpp
index ca2ae6665ce8..773230263da8 100644
--- a/lib/DebugInfo/PDB/PDBContext.cpp
+++ b/lib/DebugInfo/PDB/PDBContext.cpp
@@ -19,6 +19,7 @@
using namespace llvm;
using namespace llvm::object;
+using namespace llvm::pdb;
PDBContext::PDBContext(const COFFObjectFile &Object,
std::unique_ptr<IPDBSession> PDBSession)
@@ -28,7 +29,8 @@ PDBContext::PDBContext(const COFFObjectFile &Object,
Session->setLoadAddress(ImageBase.get());
}
-void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType) {}
+void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType,
+ bool DumpEH) {}
DILineInfo PDBContext::getLineInfoForAddress(uint64_t Address,
DILineInfoSpecifier Specifier) {
@@ -95,26 +97,24 @@ std::string PDBContext::getFunctionName(uint64_t Address,
if (NameKind == DINameKind::None)
return std::string();
+ std::unique_ptr<PDBSymbol> FuncSymbol =
+ Session->findSymbolByAddress(Address, PDB_SymType::Function);
+ auto *Func = dyn_cast_or_null<PDBSymbolFunc>(FuncSymbol.get());
+
if (NameKind == DINameKind::LinkageName) {
// It is not possible to get the mangled linkage name through a
// PDBSymbolFunc. For that we have to specifically request a
// PDBSymbolPublicSymbol.
auto PublicSym =
Session->findSymbolByAddress(Address, PDB_SymType::PublicSymbol);
- if (auto PS = dyn_cast_or_null<PDBSymbolPublicSymbol>(PublicSym.get()))
- return PS->getName();
+ if (auto *PS = dyn_cast_or_null<PDBSymbolPublicSymbol>(PublicSym.get())) {
+ // If we also have a function symbol, prefer the use of public symbol name
+ // only if it refers to the same address. The public symbol uses the
+ // linkage name while the function does not.
+ if (!Func || Func->getVirtualAddress() == PS->getVirtualAddress())
+ return PS->getName();
+ }
}
- auto FuncSymbol =
- Session->findSymbolByAddress(Address, PDB_SymType::Function);
-
- // This could happen either if there was no public symbol (e.g. not
- // external) or the user requested the short name. In the former case,
- // although they technically requested the linkage name, if the linkage
- // name is not available we fallback to at least returning a non-empty
- // string.
- if (auto Func = dyn_cast_or_null<PDBSymbolFunc>(FuncSymbol.get()))
- return Func->getName();
-
- return std::string();
+ return Func ? Func->getName() : std::string();
}
diff --git a/lib/DebugInfo/PDB/PDBExtras.cpp b/lib/DebugInfo/PDB/PDBExtras.cpp
index 4b9437c58243..b7eee6e53941 100644
--- a/lib/DebugInfo/PDB/PDBExtras.cpp
+++ b/lib/DebugInfo/PDB/PDBExtras.cpp
@@ -12,6 +12,7 @@
#include "llvm/ADT/ArrayRef.h"
using namespace llvm;
+using namespace llvm::pdb;
#define CASE_OUTPUT_ENUM_CLASS_STR(Class, Value, Str, Stream) \
case Class::Value: \
@@ -21,7 +22,8 @@ using namespace llvm;
#define CASE_OUTPUT_ENUM_CLASS_NAME(Class, Value, Stream) \
CASE_OUTPUT_ENUM_CLASS_STR(Class, Value, #Value, Stream)
-raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_VariantType &Type) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const PDB_VariantType &Type) {
switch (Type) {
CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Bool, OS)
CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Single, OS)
@@ -40,42 +42,39 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_VariantType &Type) {
return OS;
}
-raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_CallingConv &Conv) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const PDB_CallingConv &Conv) {
OS << "__";
switch (Conv) {
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearCdecl, "cdecl", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarCdecl, "cdecl", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearPascal, "pascal", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarPascal, "pascal", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearFastcall, "fastcall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarFastcall, "fastcall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Skipped, "skippedcall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearStdcall, "stdcall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarStdcall, "stdcall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearSyscall, "syscall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarSyscall, "syscall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Thiscall, "thiscall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, MipsCall, "mipscall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Generic, "genericcall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Alphacall, "alphacall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Ppccall, "ppccall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, SuperHCall, "superhcall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Armcall, "armcall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, AM33call, "am33call", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Tricall, "tricall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Sh5call, "sh5call", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, M32R, "m32rcall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Clrcall, "clrcall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Inline, "inlinecall", OS)
- CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearVectorcall, "vectorcall",
- OS)
- default:
- OS << "unknowncall";
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearC , "cdecl", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarC , "cdecl", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearPascal , "pascal", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarPascal , "pascal", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearFast , "fastcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarFast , "fastcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearStdCall, "stdcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarStdCall , "stdcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearSysCall, "syscall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarSysCall , "syscall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ThisCall , "thiscall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, MipsCall , "mipscall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Generic , "genericcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, AlphaCall , "alphacall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, PpcCall , "ppccall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, SHCall , "superhcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ArmCall , "armcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, AM33Call , "am33call", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, TriCall , "tricall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, SH5Call , "sh5call", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, M32RCall , "m32rcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ClrCall , "clrcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Inline , "inlinecall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearVector , "vectorcall", OS)
}
return OS;
}
-raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_DataKind &Data) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_DataKind &Data) {
switch (Data) {
CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Unknown, "unknown", OS)
CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Local, "local", OS)
@@ -91,62 +90,63 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_DataKind &Data) {
return OS;
}
-raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_RegisterId &Reg) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const codeview::RegisterId &Reg) {
switch (Reg) {
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, AL, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, CL, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, DL, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, BL, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, AH, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, CH, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, DH, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, BH, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, AX, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, CX, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, DX, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, BX, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, SP, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, BP, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, SI, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, DI, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, EAX, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, ECX, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, EDX, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, EBX, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, ESP, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, EBP, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, ESI, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, EDI, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, ES, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, CS, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, SS, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, DS, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, FS, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, GS, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, IP, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, RAX, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, RBX, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, RCX, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, RDX, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, RSI, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, RDI, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, RBP, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, RSP, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, R8, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, R9, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, R10, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, R11, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, R12, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, R13, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, R14, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_RegisterId, R15, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, AL, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, CL, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, DL, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, BL, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, AH, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, CH, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, DH, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, BH, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, AX, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, CX, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, DX, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, BX, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, SP, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, BP, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, SI, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, DI, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, EAX, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, ECX, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, EDX, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, EBX, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, ESP, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, EBP, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, ESI, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, EDI, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, ES, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, CS, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, SS, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, DS, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, FS, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, GS, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, IP, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, RAX, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, RBX, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, RCX, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, RDX, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, RSI, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, RDI, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, RBP, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, RSP, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, R8, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, R9, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, R10, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, R11, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, R12, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, R13, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, R14, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::RegisterId, R15, OS)
default:
OS << static_cast<int>(Reg);
}
return OS;
}
-raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_LocType &Loc) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_LocType &Loc) {
switch (Loc) {
CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Static, "static", OS)
CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, TLS, "tls", OS)
@@ -164,20 +164,22 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_LocType &Loc) {
return OS;
}
-raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_ThunkOrdinal &Thunk) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const codeview::ThunkOrdinal &Thunk) {
switch (Thunk) {
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_ThunkOrdinal, BranchIsland, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_ThunkOrdinal, Pcode, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_ThunkOrdinal, Standard, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_ThunkOrdinal, ThisAdjustor, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_ThunkOrdinal, TrampIncremental, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_ThunkOrdinal, UnknownLoad, OS)
- CASE_OUTPUT_ENUM_CLASS_NAME(PDB_ThunkOrdinal, Vcall, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, BranchIsland, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Pcode, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Standard, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, ThisAdjustor, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, TrampIncremental, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, UnknownLoad, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Vcall, OS)
}
return OS;
}
-raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_Checksum &Checksum) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const PDB_Checksum &Checksum) {
switch (Checksum) {
CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, None, OS)
CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, MD5, OS)
@@ -186,7 +188,7 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_Checksum &Checksum) {
return OS;
}
-raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_Lang &Lang) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_Lang &Lang) {
switch (Lang) {
CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, C, OS)
CASE_OUTPUT_ENUM_CLASS_STR(PDB_Lang, Cpp, "C++", OS)
@@ -209,7 +211,7 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_Lang &Lang) {
return OS;
}
-raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_SymType &Tag) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_SymType &Tag) {
switch (Tag) {
CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Exe, OS)
CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Compiland, OS)
@@ -247,7 +249,8 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_SymType &Tag) {
return OS;
}
-raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_MemberAccess &Access) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const PDB_MemberAccess &Access) {
switch (Access) {
CASE_OUTPUT_ENUM_CLASS_STR(PDB_MemberAccess, Public, "public", OS)
CASE_OUTPUT_ENUM_CLASS_STR(PDB_MemberAccess, Protected, "protected", OS)
@@ -256,7 +259,7 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_MemberAccess &Access) {
return OS;
}
-raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_UdtType &Type) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_UdtType &Type) {
switch (Type) {
CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Class, "class", OS)
CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Struct, "struct", OS)
@@ -266,7 +269,7 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_UdtType &Type) {
return OS;
}
-raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_UniqueId &Id) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_UniqueId &Id) {
static const char *Lookup = "0123456789ABCDEF";
static_assert(sizeof(PDB_UniqueId) == 16, "Expected 16-byte GUID");
@@ -285,40 +288,72 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const PDB_UniqueId &Id) {
return OS;
}
-raw_ostream &llvm::operator<<(raw_ostream &OS, const Variant &Value) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const PDB_Machine &Machine) {
+ switch (Machine) {
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Am33, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Amd64, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Arm, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, ArmNT, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Ebc, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, x86, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Ia64, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, M32R, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Mips16, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, MipsFpu, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, MipsFpu16, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, PowerPC, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, PowerPCFP, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, R4000, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH3, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH3DSP, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH4, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH5, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Thumb, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, WceMipsV2, OS)
+ default:
+ OS << "Unknown";
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const Variant &Value) {
switch (Value.Type) {
case PDB_VariantType::Bool:
- OS << (Value.Bool ? "true" : "false");
+ OS << (Value.Value.Bool ? "true" : "false");
break;
case PDB_VariantType::Double:
- OS << Value.Double;
+ OS << Value.Value.Double;
break;
case PDB_VariantType::Int16:
- OS << Value.Int16;
+ OS << Value.Value.Int16;
break;
case PDB_VariantType::Int32:
- OS << Value.Int32;
+ OS << Value.Value.Int32;
break;
case PDB_VariantType::Int64:
- OS << Value.Int64;
+ OS << Value.Value.Int64;
break;
case PDB_VariantType::Int8:
- OS << static_cast<int>(Value.Int8);
+ OS << static_cast<int>(Value.Value.Int8);
break;
case PDB_VariantType::Single:
- OS << Value.Single;
+ OS << Value.Value.Single;
break;
case PDB_VariantType::UInt16:
- OS << Value.Double;
+ OS << Value.Value.Double;
break;
case PDB_VariantType::UInt32:
- OS << Value.UInt32;
+ OS << Value.Value.UInt32;
break;
case PDB_VariantType::UInt64:
- OS << Value.UInt64;
+ OS << Value.Value.UInt64;
break;
case PDB_VariantType::UInt8:
- OS << static_cast<unsigned>(Value.UInt8);
+ OS << static_cast<unsigned>(Value.Value.UInt8);
+ break;
+ case PDB_VariantType::String:
+ OS << Value.Value.String;
break;
default:
OS << Value.Type;
@@ -326,12 +361,13 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const Variant &Value) {
return OS;
}
-raw_ostream &llvm::operator<<(raw_ostream &OS, const VersionInfo &Version) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const VersionInfo &Version) {
OS << Version.Major << "." << Version.Minor << "." << Version.Build;
return OS;
}
-raw_ostream &llvm::operator<<(raw_ostream &OS, const TagStats &Stats) {
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const TagStats &Stats) {
for (auto Tag : Stats) {
OS << Tag.first << ":" << Tag.second << " ";
}
diff --git a/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp b/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp
index 7b6268d8f655..a347c67ba8e1 100644
--- a/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp
+++ b/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp
@@ -18,6 +18,7 @@
#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
using namespace llvm;
+using namespace llvm::pdb;
IPDBSession::~IPDBSession() {}
diff --git a/lib/DebugInfo/PDB/PDBSymDumper.cpp b/lib/DebugInfo/PDB/PDBSymDumper.cpp
index 121e2d13d0c1..9450a988dd6f 100644
--- a/lib/DebugInfo/PDB/PDBSymDumper.cpp
+++ b/lib/DebugInfo/PDB/PDBSymDumper.cpp
@@ -11,6 +11,7 @@
#include "llvm/Support/ErrorHandling.h"
using namespace llvm;
+using namespace llvm::pdb;
#define PDB_SYMDUMP_UNREACHABLE(Type) \
if (RequireImpl) \
diff --git a/lib/DebugInfo/PDB/PDBSymbol.cpp b/lib/DebugInfo/PDB/PDBSymbol.cpp
index f9aaf3ae934d..78b3afc6079a 100644
--- a/lib/DebugInfo/PDB/PDBSymbol.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbol.cpp
@@ -50,6 +50,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbol::PDBSymbol(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol)
@@ -112,6 +113,7 @@ void PDBSymbol::defaultDump(raw_ostream &OS, int Indent) const {
}
PDB_SymType PDBSymbol::getSymTag() const { return RawSymbol->getSymTag(); }
+uint32_t PDBSymbol::getSymIndexId() const { return RawSymbol->getSymIndexId(); }
std::unique_ptr<IPDBEnumSymbols> PDBSymbol::findAllChildren() const {
return findAllChildren(PDB_SymType::None);
diff --git a/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp b/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp
index a782cad00ae9..cdb167b6191c 100644
--- a/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp
@@ -14,6 +14,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolAnnotation::PDBSymbolAnnotation(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolBlock.cpp b/lib/DebugInfo/PDB/PDBSymbolBlock.cpp
index 46b0ea553e7b..fd5dc9427abf 100644
--- a/lib/DebugInfo/PDB/PDBSymbolBlock.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolBlock.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolBlock::PDBSymbolBlock(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp b/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp
index 74369148e26e..ebff08846cac 100644
--- a/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp
@@ -8,12 +8,14 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h"
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolCompiland::PDBSymbolCompiland(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol)
@@ -22,3 +24,21 @@ PDBSymbolCompiland::PDBSymbolCompiland(const IPDBSession &PDBSession,
void PDBSymbolCompiland::dump(PDBSymDumper &Dumper) const {
Dumper.dump(*this);
}
+
+std::string PDBSymbolCompiland::getSourceFileName() const
+{
+ std::string Result = RawSymbol->getSourceFileName();
+ if (!Result.empty())
+ return Result;
+ auto Envs = findAllChildren<PDBSymbolCompilandEnv>();
+ if (!Envs)
+ return std::string();
+ while (auto Env = Envs->getNext()) {
+ std::string Var = Env->getName();
+ if (Var != "src")
+ continue;
+ std::string Value = Env->getValue();
+ return Value;
+ }
+ return std::string();
+}
diff --git a/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp b/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp
index 7b351a042d05..6dbd5228f2cd 100644
--- a/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolCompilandDetails::PDBSymbolCompilandDetails(
const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp b/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp
index e863ccf1ffa3..9c7f0b1be56f 100644
--- a/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp
@@ -16,14 +16,17 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolCompilandEnv::PDBSymbolCompilandEnv(
const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol)
: PDBSymbol(PDBSession, std::move(Symbol)) {}
std::string PDBSymbolCompilandEnv::getValue() const {
- // call RawSymbol->getValue() and convert the result to an std::string.
- return std::string();
+ Variant Value = RawSymbol->getValue();
+ if (Value.Type != PDB_VariantType::String)
+ return std::string();
+ return std::string(Value.Value.String);
}
void PDBSymbolCompilandEnv::dump(PDBSymDumper &Dumper) const {
diff --git a/lib/DebugInfo/PDB/PDBSymbolCustom.cpp b/lib/DebugInfo/PDB/PDBSymbolCustom.cpp
index bd7d9cda2181..0ea387a0eabb 100644
--- a/lib/DebugInfo/PDB/PDBSymbolCustom.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolCustom.cpp
@@ -16,6 +16,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolCustom::PDBSymbolCustom(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> CustomSymbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolData.cpp b/lib/DebugInfo/PDB/PDBSymbolData.cpp
index a948c2d08afb..62bb6f3f41e2 100644
--- a/lib/DebugInfo/PDB/PDBSymbolData.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolData.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolData::PDBSymbolData(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> DataSymbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolExe.cpp b/lib/DebugInfo/PDB/PDBSymbolExe.cpp
index c9e34ea501dd..60101c168a79 100644
--- a/lib/DebugInfo/PDB/PDBSymbolExe.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolExe.cpp
@@ -14,6 +14,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolExe::PDBSymbolExe(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolFunc.cpp b/lib/DebugInfo/PDB/PDBSymbolFunc.cpp
index 0aff327366cb..35251c0cc1c1 100644
--- a/lib/DebugInfo/PDB/PDBSymbolFunc.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolFunc.cpp
@@ -23,6 +23,7 @@
#include <vector>
using namespace llvm;
+using namespace llvm::pdb;
namespace {
class FunctionArgEnumerator : public IPDBEnumChildren<PDBSymbolData> {
diff --git a/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp b/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp
index 8e559b324059..77e996f651df 100644
--- a/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolFuncDebugEnd::PDBSymbolFuncDebugEnd(
const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp b/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp
index ff4254f11504..9c653879176b 100644
--- a/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolFuncDebugStart::PDBSymbolFuncDebugStart(
const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolLabel.cpp b/lib/DebugInfo/PDB/PDBSymbolLabel.cpp
index f39dee8d949a..d2cfd11c35e4 100644
--- a/lib/DebugInfo/PDB/PDBSymbolLabel.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolLabel.cpp
@@ -14,6 +14,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolLabel::PDBSymbolLabel(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp b/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp
index bd6fe89ac325..97d668740818 100644
--- a/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolPublicSymbol::PDBSymbolPublicSymbol(
const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolThunk.cpp b/lib/DebugInfo/PDB/PDBSymbolThunk.cpp
index 733eb5f75031..ef8897d12af4 100644
--- a/lib/DebugInfo/PDB/PDBSymbolThunk.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolThunk.cpp
@@ -14,6 +14,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolThunk::PDBSymbolThunk(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp
index 19809650361f..c010cc5d7678 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolTypeArray::PDBSymbolTypeArray(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp
index c1f0d2f6db11..382c397b24d2 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolTypeBaseClass::PDBSymbolTypeBaseClass(
const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp
index b302b6629898..e5d65bf5d1fd 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp
@@ -14,6 +14,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolTypeBuiltin::PDBSymbolTypeBuiltin(
const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp
index cc391f1856c8..1d80c97f9ede 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolTypeCustom::PDBSymbolTypeCustom(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp
index 1e19d0b00122..535d97dcd21e 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp
@@ -16,6 +16,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolTypeDimension::PDBSymbolTypeDimension(
const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp
index 8dd26a342e73..788f2b732aaa 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp
@@ -17,6 +17,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolTypeEnum::PDBSymbolTypeEnum(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp
index d33266094542..5831baebb993 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolTypeFriend::PDBSymbolTypeFriend(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp
index f8f71ead88b9..c6f586db9e57 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp
@@ -14,6 +14,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolTypeFunctionArg::PDBSymbolTypeFunctionArg(
const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp
index af3563f891f8..057ae260885f 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp
@@ -19,6 +19,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
namespace {
class FunctionArgEnumerator : public IPDBEnumSymbols {
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp
index a7fac3030e99..072d2cfd42fb 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolTypeManaged::PDBSymbolTypeManaged(
const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp b/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp
index 082ed83fcf4e..699771450a5d 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolTypePointer::PDBSymbolTypePointer(
const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp
index 5a426993869d..0f283b9e21a4 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp
@@ -14,6 +14,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolTypeTypedef::PDBSymbolTypeTypedef(
const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp
index 2b5da295fde3..c71838cc7a6f 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp
@@ -14,6 +14,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolTypeUDT::PDBSymbolTypeUDT(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp
index b465d023c59e..6b76db5912ce 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp
@@ -14,6 +14,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolTypeVTable::PDBSymbolTypeVTable(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp
index 16052f1e6810..ef509d64bf60 100644
--- a/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolTypeVTableShape::PDBSymbolTypeVTableShape(
const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp b/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp
index 48dc11558ccb..dbbea9c93e20 100644
--- a/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolUnknown::PDBSymbolUnknown(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp b/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp
index 6cf13de08512..6a62d554f42c 100644
--- a/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp
+++ b/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp
@@ -15,6 +15,7 @@
#include <utility>
using namespace llvm;
+using namespace llvm::pdb;
PDBSymbolUsingNamespace::PDBSymbolUsingNamespace(
const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol)
diff --git a/lib/DebugInfo/PDB/Raw/DbiStream.cpp b/lib/DebugInfo/PDB/Raw/DbiStream.cpp
new file mode 100644
index 000000000000..3c0586c728f9
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/DbiStream.cpp
@@ -0,0 +1,462 @@
+//===- DbiStream.cpp - PDB Dbi Stream (Stream 3) Access -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
+
+#include "llvm/DebugInfo/CodeView/StreamArray.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/CodeView/StreamWriter.h"
+#include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h"
+#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
+#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
+#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h"
+#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
+#include "llvm/Object/COFF.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+using namespace llvm::support;
+
+namespace {
+// Some of the values are stored in bitfields. Since this needs to be portable
+// across compilers and architectures (big / little endian in particular) we
+// can't use the actual structures below, but must instead do the shifting
+// and masking ourselves. The struct definitions are provided for reference.
+
+// struct DbiFlags {
+// uint16_t IncrementalLinking : 1; // True if linked incrementally
+// uint16_t IsStripped : 1; // True if private symbols were stripped.
+// uint16_t HasCTypes : 1; // True if linked with /debug:ctypes.
+// uint16_t Reserved : 13;
+//};
+const uint16_t FlagIncrementalMask = 0x0001;
+const uint16_t FlagStrippedMask = 0x0002;
+const uint16_t FlagHasCTypesMask = 0x0004;
+
+// struct DbiBuildNo {
+// uint16_t MinorVersion : 8;
+// uint16_t MajorVersion : 7;
+// uint16_t NewVersionFormat : 1;
+//};
+const uint16_t BuildMinorMask = 0x00FF;
+const uint16_t BuildMinorShift = 0;
+
+const uint16_t BuildMajorMask = 0x7F00;
+const uint16_t BuildMajorShift = 8;
+
+struct FileInfoSubstreamHeader {
+ ulittle16_t NumModules; // Total # of modules, should match number of
+ // records in the ModuleInfo substream.
+ ulittle16_t NumSourceFiles; // Total # of source files. This value is not
+ // accurate because PDB actually supports more
+ // than 64k source files, so we ignore it and
+ // compute the value from other stream fields.
+};
+}
+
+template <typename ContribType>
+static Error loadSectionContribs(FixedStreamArray<ContribType> &Output,
+ StreamReader &Reader) {
+ if (Reader.bytesRemaining() % sizeof(ContribType) != 0)
+ return make_error<RawError>(
+ raw_error_code::corrupt_file,
+ "Invalid number of bytes of section contributions");
+
+ uint32_t Count = Reader.bytesRemaining() / sizeof(ContribType);
+ if (auto EC = Reader.readArray(Output, Count))
+ return EC;
+ return Error::success();
+}
+
+DbiStream::DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream)
+ : Pdb(File), Stream(std::move(Stream)), Header(nullptr) {
+ static_assert(sizeof(HeaderInfo) == 64, "Invalid HeaderInfo size!");
+}
+
+DbiStream::~DbiStream() {}
+
+Error DbiStream::reload() {
+ StreamReader Reader(*Stream);
+
+ if (Stream->getLength() < sizeof(HeaderInfo))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI Stream does not contain a header.");
+ if (auto EC = Reader.readObject(Header))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI Stream does not contain a header.");
+
+ if (Header->VersionSignature != -1)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid DBI version signature.");
+
+ // Require at least version 7, which should be present in all PDBs
+ // produced in the last decade and allows us to avoid having to
+ // special case all kinds of complicated arcane formats.
+ if (Header->VersionHeader < PdbDbiV70)
+ return make_error<RawError>(raw_error_code::feature_unsupported,
+ "Unsupported DBI version.");
+
+ auto IS = Pdb.getPDBInfoStream();
+ if (!IS)
+ return IS.takeError();
+
+ if (Header->Age != IS->getAge())
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI Age does not match PDB Age.");
+
+ if (Stream->getLength() !=
+ sizeof(HeaderInfo) + Header->ModiSubstreamSize +
+ Header->SecContrSubstreamSize + Header->SectionMapSize +
+ Header->FileInfoSize + Header->TypeServerSize +
+ Header->OptionalDbgHdrSize + Header->ECSubstreamSize)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI Length does not equal sum of substreams.");
+
+ // Only certain substreams are guaranteed to be aligned. Validate
+ // them here.
+ if (Header->ModiSubstreamSize % sizeof(uint32_t) != 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI MODI substream not aligned.");
+ if (Header->SecContrSubstreamSize % sizeof(uint32_t) != 0)
+ return make_error<RawError>(
+ raw_error_code::corrupt_file,
+ "DBI section contribution substream not aligned.");
+ if (Header->SectionMapSize % sizeof(uint32_t) != 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI section map substream not aligned.");
+ if (Header->FileInfoSize % sizeof(uint32_t) != 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI file info substream not aligned.");
+ if (Header->TypeServerSize % sizeof(uint32_t) != 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI type server substream not aligned.");
+
+ // Since each ModInfo in the stream is a variable length, we have to iterate
+ // them to know how many there actually are.
+ VarStreamArray<ModInfo> ModInfoArray;
+ if (auto EC = Reader.readArray(ModInfoArray, Header->ModiSubstreamSize))
+ return EC;
+ for (auto &Info : ModInfoArray) {
+ ModuleInfos.emplace_back(Info);
+ }
+
+ if (auto EC = Reader.readStreamRef(SecContrSubstream,
+ Header->SecContrSubstreamSize))
+ return EC;
+ if (auto EC = Reader.readStreamRef(SecMapSubstream, Header->SectionMapSize))
+ return EC;
+ if (auto EC = Reader.readStreamRef(FileInfoSubstream, Header->FileInfoSize))
+ return EC;
+ if (auto EC =
+ Reader.readStreamRef(TypeServerMapSubstream, Header->TypeServerSize))
+ return EC;
+ if (auto EC = Reader.readStreamRef(ECSubstream, Header->ECSubstreamSize))
+ return EC;
+ if (auto EC = Reader.readArray(DbgStreams, Header->OptionalDbgHdrSize /
+ sizeof(ulittle16_t)))
+ return EC;
+
+ if (auto EC = initializeSectionContributionData())
+ return EC;
+ if (auto EC = initializeSectionHeadersData())
+ return EC;
+ if (auto EC = initializeSectionMapData())
+ return EC;
+ if (auto EC = initializeFileInfo())
+ return EC;
+ if (auto EC = initializeFpoRecords())
+ return EC;
+
+ if (Reader.bytesRemaining() > 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Found unexpected bytes in DBI Stream.");
+
+ if (ECSubstream.getLength() > 0) {
+ StreamReader ECReader(ECSubstream);
+ if (auto EC = ECNames.load(ECReader))
+ return EC;
+ }
+
+ return Error::success();
+}
+
+PdbRaw_DbiVer DbiStream::getDbiVersion() const {
+ uint32_t Value = Header->VersionHeader;
+ return static_cast<PdbRaw_DbiVer>(Value);
+}
+
+uint32_t DbiStream::getAge() const { return Header->Age; }
+
+uint16_t DbiStream::getPublicSymbolStreamIndex() const {
+ return Header->PublicSymbolStreamIndex;
+}
+
+uint16_t DbiStream::getGlobalSymbolStreamIndex() const {
+ return Header->GlobalSymbolStreamIndex;
+}
+
+uint16_t DbiStream::getFlags() const { return Header->Flags; }
+
+bool DbiStream::isIncrementallyLinked() const {
+ return (Header->Flags & FlagIncrementalMask) != 0;
+}
+
+bool DbiStream::hasCTypes() const {
+ return (Header->Flags & FlagHasCTypesMask) != 0;
+}
+
+bool DbiStream::isStripped() const {
+ return (Header->Flags & FlagStrippedMask) != 0;
+}
+
+uint16_t DbiStream::getBuildNumber() const { return Header->BuildNumber; }
+
+uint16_t DbiStream::getBuildMajorVersion() const {
+ return (Header->BuildNumber & BuildMajorMask) >> BuildMajorShift;
+}
+
+uint16_t DbiStream::getBuildMinorVersion() const {
+ return (Header->BuildNumber & BuildMinorMask) >> BuildMinorShift;
+}
+
+uint16_t DbiStream::getPdbDllRbld() const { return Header->PdbDllRbld; }
+
+uint32_t DbiStream::getPdbDllVersion() const { return Header->PdbDllVersion; }
+
+uint32_t DbiStream::getSymRecordStreamIndex() const {
+ return Header->SymRecordStreamIndex;
+}
+
+PDB_Machine DbiStream::getMachineType() const {
+ uint16_t Machine = Header->MachineType;
+ return static_cast<PDB_Machine>(Machine);
+}
+
+codeview::FixedStreamArray<object::coff_section>
+DbiStream::getSectionHeaders() {
+ return SectionHeaders;
+}
+
+codeview::FixedStreamArray<object::FpoData> DbiStream::getFpoRecords() {
+ return FpoRecords;
+}
+
+ArrayRef<ModuleInfoEx> DbiStream::modules() const { return ModuleInfos; }
+codeview::FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const {
+ return SectionMap;
+}
+
+void llvm::pdb::DbiStream::visitSectionContributions(
+ ISectionContribVisitor &Visitor) const {
+ if (SectionContribVersion == DbiSecContribVer60) {
+ for (auto &SC : SectionContribs)
+ Visitor.visit(SC);
+ } else if (SectionContribVersion == DbiSecContribV2) {
+ for (auto &SC : SectionContribs2)
+ Visitor.visit(SC);
+ }
+}
+
+Error DbiStream::initializeSectionContributionData() {
+ if (SecContrSubstream.getLength() == 0)
+ return Error::success();
+
+ StreamReader SCReader(SecContrSubstream);
+ if (auto EC = SCReader.readEnum(SectionContribVersion))
+ return EC;
+
+ if (SectionContribVersion == DbiSecContribVer60)
+ return loadSectionContribs<SectionContrib>(SectionContribs, SCReader);
+ if (SectionContribVersion == DbiSecContribV2)
+ return loadSectionContribs<SectionContrib2>(SectionContribs2, SCReader);
+
+ return make_error<RawError>(raw_error_code::feature_unsupported,
+ "Unsupported DBI Section Contribution version");
+}
+
+// Initializes this->SectionHeaders.
+Error DbiStream::initializeSectionHeadersData() {
+ if (DbgStreams.size() == 0)
+ return Error::success();
+
+ uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::SectionHdr);
+ if (StreamNum >= Pdb.getNumStreams())
+ return make_error<RawError>(raw_error_code::no_stream);
+
+ auto SHS = MappedBlockStream::createIndexedStream(StreamNum, Pdb);
+ if (!SHS)
+ return SHS.takeError();
+
+ size_t StreamLen = (*SHS)->getLength();
+ if (StreamLen % sizeof(object::coff_section))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Corrupted section header stream.");
+
+ size_t NumSections = StreamLen / sizeof(object::coff_section);
+ codeview::StreamReader Reader(**SHS);
+ if (auto EC = Reader.readArray(SectionHeaders, NumSections))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read a bitmap.");
+
+ SectionHeaderStream = std::move(*SHS);
+ return Error::success();
+}
+
+// Initializes this->Fpos.
+Error DbiStream::initializeFpoRecords() {
+ if (DbgStreams.size() == 0)
+ return Error::success();
+
+ uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::NewFPO);
+
+ // This means there is no FPO data.
+ if (StreamNum == InvalidStreamIndex)
+ return Error::success();
+
+ if (StreamNum >= Pdb.getNumStreams())
+ return make_error<RawError>(raw_error_code::no_stream);
+
+ auto FS = MappedBlockStream::createIndexedStream(StreamNum, Pdb);
+ if (!FS)
+ return FS.takeError();
+
+ size_t StreamLen = (*FS)->getLength();
+ if (StreamLen % sizeof(object::FpoData))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Corrupted New FPO stream.");
+
+ size_t NumRecords = StreamLen / sizeof(object::FpoData);
+ codeview::StreamReader Reader(**FS);
+ if (auto EC = Reader.readArray(FpoRecords, NumRecords))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Corrupted New FPO stream.");
+ FpoStream = std::move(*FS);
+ return Error::success();
+}
+
+Error DbiStream::initializeSectionMapData() {
+ if (SecMapSubstream.getLength() == 0)
+ return Error::success();
+
+ StreamReader SMReader(SecMapSubstream);
+ const SecMapHeader *Header;
+ if (auto EC = SMReader.readObject(Header))
+ return EC;
+ if (auto EC = SMReader.readArray(SectionMap, Header->SecCount))
+ return EC;
+ return Error::success();
+}
+
+Error DbiStream::initializeFileInfo() {
+ // The layout of the FileInfoSubstream is like this:
+ // struct {
+ // ulittle16_t NumModules;
+ // ulittle16_t NumSourceFiles;
+ // ulittle16_t ModIndices[NumModules];
+ // ulittle16_t ModFileCounts[NumModules];
+ // ulittle32_t FileNameOffsets[NumSourceFiles];
+ // char Names[][NumSourceFiles];
+ // };
+ // with the caveat that `NumSourceFiles` cannot be trusted, so
+ // it is computed by summing `ModFileCounts`.
+ //
+ if (FileInfoSubstream.getLength() == 0)
+ return Error::success();
+
+ const FileInfoSubstreamHeader *FH;
+ StreamReader FISR(FileInfoSubstream);
+ if (auto EC = FISR.readObject(FH))
+ return EC;
+
+ // The number of modules in the stream should be the same as reported by
+ // the FileInfoSubstreamHeader.
+ if (FH->NumModules != ModuleInfos.size())
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "FileInfo substream count doesn't match DBI.");
+
+ FixedStreamArray<ulittle16_t> ModIndexArray;
+ FixedStreamArray<ulittle16_t> ModFileCountArray;
+
+ // First is an array of `NumModules` module indices. This is not used for the
+ // same reason that `NumSourceFiles` is not used. It's an array of uint16's,
+ // but it's possible there are more than 64k source files, which would imply
+ // more than 64k modules (e.g. object files) as well. So we ignore this
+ // field.
+ if (auto EC = FISR.readArray(ModIndexArray, ModuleInfos.size()))
+ return EC;
+ if (auto EC = FISR.readArray(ModFileCountArray, ModuleInfos.size()))
+ return EC;
+
+ // Compute the real number of source files.
+ uint32_t NumSourceFiles = 0;
+ for (auto Count : ModFileCountArray)
+ NumSourceFiles += Count;
+
+ // This is the array that in the reference implementation corresponds to
+ // `ModInfo::FileLayout::FileNameOffs`, which is commented there as being a
+ // pointer. Due to the mentioned problems of pointers causing difficulty
+ // when reading from the file on 64-bit systems, we continue to ignore that
+ // field in `ModInfo`, and instead build a vector of StringRefs and stores
+ // them in `ModuleInfoEx`. The value written to and read from the file is
+ // not used anyway, it is only there as a way to store the offsets for the
+ // purposes of later accessing the names at runtime.
+ if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))
+ return EC;
+
+ if (auto EC = FISR.readStreamRef(NamesBuffer))
+ return EC;
+
+ // We go through each ModuleInfo, determine the number N of source files for
+ // that module, and then get the next N offsets from the Offsets array, using
+ // them to get the corresponding N names from the Names buffer and associating
+ // each one with the corresponding module.
+ uint32_t NextFileIndex = 0;
+ for (size_t I = 0; I < ModuleInfos.size(); ++I) {
+ uint32_t NumFiles = ModFileCountArray[I];
+ ModuleInfos[I].SourceFiles.resize(NumFiles);
+ for (size_t J = 0; J < NumFiles; ++J, ++NextFileIndex) {
+ auto ThisName = getFileNameForIndex(NextFileIndex);
+ if (!ThisName)
+ return ThisName.takeError();
+ ModuleInfos[I].SourceFiles[J] = *ThisName;
+ }
+ }
+
+ return Error::success();
+}
+
+uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type) const {
+ return DbgStreams[static_cast<uint16_t>(Type)];
+}
+
+Expected<StringRef> DbiStream::getFileNameForIndex(uint32_t Index) const {
+ StreamReader Names(NamesBuffer);
+ if (Index >= FileNameOffsets.size())
+ return make_error<RawError>(raw_error_code::index_out_of_bounds);
+
+ uint32_t FileOffset = FileNameOffsets[Index];
+ Names.setOffset(FileOffset);
+ StringRef Name;
+ if (auto EC = Names.readZeroString(Name))
+ return std::move(EC);
+ return Name;
+}
+
+Error DbiStream::commit() {
+ StreamWriter Writer(*Stream);
+ if (auto EC = Writer.writeObject(*Header))
+ return EC;
+
+ return Error::success();
+}
diff --git a/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp b/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp
new file mode 100644
index 000000000000..34ff8ae3a907
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp
@@ -0,0 +1,81 @@
+//===- DbiStreamBuilder.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h"
+
+#include "llvm/DebugInfo/CodeView/StreamWriter.h"
+#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+DbiStreamBuilder::DbiStreamBuilder()
+ : Age(1), BuildNumber(0), PdbDllVersion(0), PdbDllRbld(0), Flags(0),
+ MachineType(PDB_Machine::x86) {}
+
+void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; }
+
+void DbiStreamBuilder::setAge(uint32_t A) { Age = A; }
+
+void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; }
+
+void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; }
+
+void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; }
+
+void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; }
+
+void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; }
+
+uint32_t DbiStreamBuilder::calculateSerializedLength() const {
+ // For now we only support serializing the header.
+ return sizeof(DbiStream::HeaderInfo);
+}
+
+Expected<std::unique_ptr<DbiStream>> DbiStreamBuilder::build(PDBFile &File) {
+ if (!VerHeader.hasValue())
+ return make_error<RawError>(raw_error_code::unspecified,
+ "Missing DBI Stream Version");
+
+ auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, File);
+ if (!DbiS)
+ return DbiS.takeError();
+ auto DS = std::move(*DbiS);
+ DbiStream::HeaderInfo *H =
+ static_cast<DbiStream::HeaderInfo *>(DS->getAllocator().Allocate(
+ sizeof(DbiStream::HeaderInfo),
+ llvm::AlignOf<DbiStream::HeaderInfo>::Alignment));
+ H->VersionHeader = *VerHeader;
+ H->VersionSignature = -1;
+ H->Age = Age;
+ H->BuildNumber = BuildNumber;
+ H->Flags = Flags;
+ H->PdbDllRbld = PdbDllRbld;
+ H->PdbDllVersion = PdbDllVersion;
+ H->MachineType = static_cast<uint16_t>(MachineType);
+
+ H->ECSubstreamSize = 0;
+ H->FileInfoSize = 0;
+ H->ModiSubstreamSize = 0;
+ H->OptionalDbgHdrSize = 0;
+ H->SecContrSubstreamSize = 0;
+ H->SectionMapSize = 0;
+ H->TypeServerSize = 0;
+ H->SymRecordStreamIndex = DbiStream::InvalidStreamIndex;
+ H->PublicSymbolStreamIndex = DbiStream::InvalidStreamIndex;
+ H->MFCTypeServerIndex = DbiStream::InvalidStreamIndex;
+ H->GlobalSymbolStreamIndex = DbiStream::InvalidStreamIndex;
+
+ auto Dbi = llvm::make_unique<DbiStream>(File, std::move(DS));
+ Dbi->Header = H;
+ return std::move(Dbi);
+}
diff --git a/lib/DebugInfo/PDB/Raw/EnumTables.cpp b/lib/DebugInfo/PDB/Raw/EnumTables.cpp
new file mode 100644
index 000000000000..fc9270c69947
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/EnumTables.cpp
@@ -0,0 +1,38 @@
+//===- EnumTables.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/EnumTables.h"
+#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+#define PDB_ENUM_CLASS_ENT(enum_class, enum) \
+ { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
+
+#define PDB_ENUM_ENT(ns, enum) \
+ { #enum, ns::enum }
+
+static const EnumEntry<uint16_t> OMFSegMapDescFlagNames[] = {
+ PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Read),
+ PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Write),
+ PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Execute),
+ PDB_ENUM_CLASS_ENT(OMFSegDescFlags, AddressIs32Bit),
+ PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsSelector),
+ PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsAbsoluteAddress),
+ PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsGroup),
+};
+
+namespace llvm {
+namespace pdb {
+ArrayRef<EnumEntry<uint16_t>> getOMFSegMapDescFlagNames() {
+ return makeArrayRef(OMFSegMapDescFlagNames);
+}
+}
+} \ No newline at end of file
diff --git a/lib/DebugInfo/PDB/Raw/Hash.cpp b/lib/DebugInfo/PDB/Raw/Hash.cpp
new file mode 100644
index 000000000000..23cb55786d78
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/Hash.cpp
@@ -0,0 +1,131 @@
+//===- Hash.cpp - PDB Hash Functions --------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/Hash.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support;
+
+// Corresponds to `Hasher::lhashPbCb` in PDB/include/misc.h.
+// Used for name hash table and TPI/IPI hashes.
+uint32_t pdb::hashStringV1(StringRef Str) {
+ uint32_t Result = 0;
+ uint32_t Size = Str.size();
+
+ ArrayRef<ulittle32_t> Longs(reinterpret_cast<const ulittle32_t *>(Str.data()),
+ Size / 4);
+
+ for (auto Value : Longs)
+ Result ^= Value;
+
+ const uint8_t *Remainder = reinterpret_cast<const uint8_t *>(Longs.end());
+ uint32_t RemainderSize = Size % 4;
+
+ // Maximum of 3 bytes left. Hash a 2 byte word if possible, then hash the
+ // possibly remaining 1 byte.
+ if (RemainderSize >= 2) {
+ uint16_t Value = *reinterpret_cast<const ulittle16_t *>(Remainder);
+ Result ^= static_cast<uint32_t>(Value);
+ Remainder += 2;
+ RemainderSize -= 2;
+ }
+
+ // hash possible odd byte
+ if (RemainderSize == 1) {
+ Result ^= *(Remainder++);
+ }
+
+ const uint32_t toLowerMask = 0x20202020;
+ Result |= toLowerMask;
+ Result ^= (Result >> 11);
+
+ return Result ^ (Result >> 16);
+}
+
+// Corresponds to `HasherV2::HashULONG` in PDB/include/misc.h.
+// Used for name hash table.
+uint32_t pdb::hashStringV2(StringRef Str) {
+ uint32_t Hash = 0xb170a1bf;
+
+ ArrayRef<char> Buffer(Str.begin(), Str.end());
+
+ ArrayRef<ulittle32_t> Items(
+ reinterpret_cast<const ulittle32_t *>(Buffer.data()),
+ Buffer.size() / sizeof(ulittle32_t));
+ for (ulittle32_t Item : Items) {
+ Hash += Item;
+ Hash += (Hash << 10);
+ Hash ^= (Hash >> 6);
+ }
+ Buffer = Buffer.slice(Items.size() * sizeof(ulittle32_t));
+ for (uint8_t Item : Buffer) {
+ Hash += Item;
+ Hash += (Hash << 10);
+ Hash ^= (Hash >> 6);
+ }
+
+ return Hash * 1664525L + 1013904223L;
+}
+
+static const uint32_t V8HashTable[] = {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
+ 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
+ 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
+ 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
+ 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
+ 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
+ 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
+ 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
+ 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
+ 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
+ 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
+ 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
+ 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
+ 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
+ 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
+ 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
+ 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
+ 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
+ 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
+ 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
+ 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
+ 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
+};
+
+// Corresponds to `SigForPbCb` in langapi/shared/crc32.h.
+uint32_t pdb::hashBufferV8(ArrayRef<uint8_t> Buf) {
+ uint32_t Hash = 0;
+ for (uint8_t Byte : Buf)
+ Hash = (Hash >> 8) ^ V8HashTable[(Hash & 0xff) ^ Byte];
+ return Hash;
+}
diff --git a/lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp b/lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp
new file mode 100644
index 000000000000..9bd16ea76efc
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp
@@ -0,0 +1,25 @@
+//===- IndexedStreamData.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
+#include "llvm/DebugInfo/PDB/Raw/IPDBFile.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+IndexedStreamData::IndexedStreamData(uint32_t StreamIdx, const IPDBFile &File)
+ : StreamIdx(StreamIdx), File(File) {}
+
+uint32_t IndexedStreamData::getLength() {
+ return File.getStreamByteSize(StreamIdx);
+}
+
+ArrayRef<support::ulittle32_t> IndexedStreamData::getStreamBlocks() {
+ return File.getStreamBlockList(StreamIdx);
+}
diff --git a/lib/DebugInfo/PDB/Raw/InfoStream.cpp b/lib/DebugInfo/PDB/Raw/InfoStream.cpp
new file mode 100644
index 000000000000..c33a764587c7
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/InfoStream.cpp
@@ -0,0 +1,90 @@
+//===- InfoStream.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/CodeView/StreamWriter.h"
+#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
+#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+InfoStream::InfoStream(std::unique_ptr<MappedBlockStream> Stream)
+ : Stream(std::move(Stream)) {}
+
+Error InfoStream::reload() {
+ codeview::StreamReader Reader(*Stream);
+
+ const HeaderInfo *H;
+ if (auto EC = Reader.readObject(H))
+ return joinErrors(
+ std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "PDB Stream does not contain a header."));
+
+ switch (H->Version) {
+ case PdbImplVC70:
+ case PdbImplVC80:
+ case PdbImplVC110:
+ case PdbImplVC140:
+ break;
+ default:
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Unsupported PDB stream version.");
+ }
+
+ Version = H->Version;
+ Signature = H->Signature;
+ Age = H->Age;
+ Guid = H->Guid;
+
+ return NamedStreams.load(Reader);
+}
+
+uint32_t InfoStream::getNamedStreamIndex(llvm::StringRef Name) const {
+ uint32_t Result;
+ if (!NamedStreams.tryGetValue(Name, Result))
+ return 0;
+ return Result;
+}
+
+iterator_range<StringMapConstIterator<uint32_t>>
+InfoStream::named_streams() const {
+ return NamedStreams.entries();
+}
+
+PdbRaw_ImplVer InfoStream::getVersion() const {
+ return static_cast<PdbRaw_ImplVer>(Version);
+}
+
+uint32_t InfoStream::getSignature() const { return Signature; }
+
+uint32_t InfoStream::getAge() const { return Age; }
+
+PDB_UniqueId InfoStream::getGuid() const { return Guid; }
+
+Error InfoStream::commit() {
+ StreamWriter Writer(*Stream);
+
+ HeaderInfo H;
+ H.Age = Age;
+ H.Signature = Signature;
+ H.Version = Version;
+ H.Guid = Guid;
+ if (auto EC = Writer.writeObject(H))
+ return EC;
+
+ return NamedStreams.commit(Writer);
+}
diff --git a/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp b/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp
new file mode 100644
index 000000000000..7be9cc32db96
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp
@@ -0,0 +1,67 @@
+//===- InfoStreamBuilder.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h"
+
+#include "llvm/DebugInfo/CodeView/StreamWriter.h"
+#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+InfoStreamBuilder::InfoStreamBuilder() {}
+
+void InfoStreamBuilder::setVersion(PdbRaw_ImplVer V) { Ver = V; }
+
+void InfoStreamBuilder::setSignature(uint32_t S) { Sig = S; }
+
+void InfoStreamBuilder::setAge(uint32_t A) { Age = A; }
+
+void InfoStreamBuilder::setGuid(PDB_UniqueId G) { Guid = G; }
+
+NameMapBuilder &InfoStreamBuilder::getNamedStreamsBuilder() {
+ return NamedStreams;
+}
+
+uint32_t InfoStreamBuilder::calculateSerializedLength() const {
+ return sizeof(InfoStream::HeaderInfo) +
+ NamedStreams.calculateSerializedLength();
+}
+
+Expected<std::unique_ptr<InfoStream>> InfoStreamBuilder::build(PDBFile &File) {
+ if (!Ver.hasValue())
+ return make_error<RawError>(raw_error_code::unspecified,
+ "Missing PDB Stream Version");
+ if (!Sig.hasValue())
+ return make_error<RawError>(raw_error_code::unspecified,
+ "Missing PDB Stream Signature");
+ if (!Age.hasValue())
+ return make_error<RawError>(raw_error_code::unspecified,
+ "Missing PDB Stream Age");
+ if (!Guid.hasValue())
+ return make_error<RawError>(raw_error_code::unspecified,
+ "Missing PDB Stream Guid");
+
+ auto InfoS = MappedBlockStream::createIndexedStream(StreamPDB, File);
+ if (!InfoS)
+ return InfoS.takeError();
+ auto Info = llvm::make_unique<InfoStream>(std::move(*InfoS));
+ Info->Version = *Ver;
+ Info->Signature = *Sig;
+ Info->Age = *Age;
+ Info->Guid = *Guid;
+ auto NS = NamedStreams.build();
+ if (!NS)
+ return NS.takeError();
+ Info->NamedStreams = **NS;
+ return std::move(Info);
+}
diff --git a/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp b/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp
new file mode 100644
index 000000000000..92b2048c3c22
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp
@@ -0,0 +1,310 @@
+//===- MappedBlockStream.cpp - Reads stream data from a PDBFile -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h"
+#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h"
+#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
+#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+namespace {
+// This exists so that we can use make_unique while still keeping the
+// constructor of MappedBlockStream private, forcing users to go through
+// the `create` interface.
+class MappedBlockStreamImpl : public MappedBlockStream {
+public:
+ MappedBlockStreamImpl(std::unique_ptr<IPDBStreamData> Data,
+ const IPDBFile &File)
+ : MappedBlockStream(std::move(Data), File) {}
+};
+}
+
+typedef std::pair<uint32_t, uint32_t> Interval;
+static Interval intersect(const Interval &I1, const Interval &I2) {
+ return std::make_pair(std::max(I1.first, I2.first),
+ std::min(I1.second, I2.second));
+}
+
+MappedBlockStream::MappedBlockStream(std::unique_ptr<IPDBStreamData> Data,
+ const IPDBFile &Pdb)
+ : Pdb(Pdb), Data(std::move(Data)) {}
+
+Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) const {
+ // Make sure we aren't trying to read beyond the end of the stream.
+ if (Size > Data->getLength())
+ return make_error<RawError>(raw_error_code::insufficient_buffer);
+ if (Offset > Data->getLength() - Size)
+ return make_error<RawError>(raw_error_code::insufficient_buffer);
+
+ if (tryReadContiguously(Offset, Size, Buffer))
+ return Error::success();
+
+ auto CacheIter = CacheMap.find(Offset);
+ if (CacheIter != CacheMap.end()) {
+ // Try to find an alloc that was large enough for this request.
+ for (auto &Entry : CacheIter->second) {
+ if (Entry.size() >= Size) {
+ Buffer = Entry.slice(0, Size);
+ return Error::success();
+ }
+ }
+ }
+
+ // We couldn't find a buffer that started at the correct offset (the most
+ // common scenario). Try to see if there is a buffer that starts at some
+ // other offset but overlaps the desired range.
+ for (auto &CacheItem : CacheMap) {
+ Interval RequestExtent = std::make_pair(Offset, Offset + Size);
+
+ // We already checked this one on the fast path above.
+ if (CacheItem.first == Offset)
+ continue;
+ // If the initial extent of the cached item is beyond the ending extent
+ // of the request, there is no overlap.
+ if (CacheItem.first >= Offset + Size)
+ continue;
+
+ // We really only have to check the last item in the list, since we append
+ // in order of increasing length.
+ if (CacheItem.second.empty())
+ continue;
+
+ auto CachedAlloc = CacheItem.second.back();
+ // If the initial extent of the request is beyond the ending extent of
+ // the cached item, there is no overlap.
+ Interval CachedExtent =
+ std::make_pair(CacheItem.first, CacheItem.first + CachedAlloc.size());
+ if (RequestExtent.first >= CachedExtent.first + CachedExtent.second)
+ continue;
+
+ Interval Intersection = intersect(CachedExtent, RequestExtent);
+ // Only use this if the entire request extent is contained in the cached
+ // extent.
+ if (Intersection != RequestExtent)
+ continue;
+
+ uint32_t CacheRangeOffset =
+ AbsoluteDifference(CachedExtent.first, Intersection.first);
+ Buffer = CachedAlloc.slice(CacheRangeOffset, Size);
+ return Error::success();
+ }
+
+ // Otherwise allocate a large enough buffer in the pool, memcpy the data
+ // into it, and return an ArrayRef to that. Do not touch existing pool
+ // allocations, as existing clients may be holding a pointer which must
+ // not be invalidated.
+ uint8_t *WriteBuffer = static_cast<uint8_t *>(Pool.Allocate(Size, 8));
+ if (auto EC = readBytes(Offset, MutableArrayRef<uint8_t>(WriteBuffer, Size)))
+ return EC;
+
+ if (CacheIter != CacheMap.end()) {
+ CacheIter->second.emplace_back(WriteBuffer, Size);
+ } else {
+ std::vector<CacheEntry> List;
+ List.emplace_back(WriteBuffer, Size);
+ CacheMap.insert(std::make_pair(Offset, List));
+ }
+ Buffer = ArrayRef<uint8_t>(WriteBuffer, Size);
+ return Error::success();
+}
+
+Error MappedBlockStream::readLongestContiguousChunk(
+ uint32_t Offset, ArrayRef<uint8_t> &Buffer) const {
+ // Make sure we aren't trying to read beyond the end of the stream.
+ if (Offset >= Data->getLength())
+ return make_error<RawError>(raw_error_code::insufficient_buffer);
+ uint32_t First = Offset / Pdb.getBlockSize();
+ uint32_t Last = First;
+
+ auto BlockList = Data->getStreamBlocks();
+ while (Last < Pdb.getBlockCount() - 1) {
+ if (BlockList[Last] != BlockList[Last + 1] - 1)
+ break;
+ ++Last;
+ }
+
+ uint32_t OffsetInFirstBlock = Offset % Pdb.getBlockSize();
+ uint32_t BytesFromFirstBlock = Pdb.getBlockSize() - OffsetInFirstBlock;
+ uint32_t BlockSpan = Last - First + 1;
+ uint32_t ByteSpan =
+ BytesFromFirstBlock + (BlockSpan - 1) * Pdb.getBlockSize();
+ auto Result = Pdb.getBlockData(BlockList[First], Pdb.getBlockSize());
+ if (!Result)
+ return Result.takeError();
+ Buffer = Result->drop_front(OffsetInFirstBlock);
+ Buffer = ArrayRef<uint8_t>(Buffer.data(), ByteSpan);
+ return Error::success();
+}
+
+uint32_t MappedBlockStream::getLength() const { return Data->getLength(); }
+
+Error MappedBlockStream::commit() const { return Error::success(); }
+
+bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) const {
+ // Attempt to fulfill the request with a reference directly into the stream.
+ // This can work even if the request crosses a block boundary, provided that
+ // all subsequent blocks are contiguous. For example, a 10k read with a 4k
+ // block size can be filled with a reference if, from the starting offset,
+ // 3 blocks in a row are contiguous.
+ uint32_t BlockNum = Offset / Pdb.getBlockSize();
+ uint32_t OffsetInBlock = Offset % Pdb.getBlockSize();
+ uint32_t BytesFromFirstBlock =
+ std::min(Size, Pdb.getBlockSize() - OffsetInBlock);
+ uint32_t NumAdditionalBlocks =
+ llvm::alignTo(Size - BytesFromFirstBlock, Pdb.getBlockSize()) /
+ Pdb.getBlockSize();
+
+ auto BlockList = Data->getStreamBlocks();
+ uint32_t RequiredContiguousBlocks = NumAdditionalBlocks + 1;
+ uint32_t E = BlockList[BlockNum];
+ for (uint32_t I = 0; I < RequiredContiguousBlocks; ++I, ++E) {
+ if (BlockList[I + BlockNum] != E)
+ return false;
+ }
+
+ uint32_t FirstBlockAddr = BlockList[BlockNum];
+ auto Result = Pdb.getBlockData(FirstBlockAddr, Pdb.getBlockSize());
+ if (!Result) {
+ consumeError(Result.takeError());
+ return false;
+ }
+ auto Data = Result->drop_front(OffsetInBlock);
+ Buffer = ArrayRef<uint8_t>(Data.data(), Size);
+ return true;
+}
+
+Error MappedBlockStream::readBytes(uint32_t Offset,
+ MutableArrayRef<uint8_t> Buffer) const {
+ uint32_t BlockNum = Offset / Pdb.getBlockSize();
+ uint32_t OffsetInBlock = Offset % Pdb.getBlockSize();
+
+ // Make sure we aren't trying to read beyond the end of the stream.
+ if (Buffer.size() > Data->getLength())
+ return make_error<RawError>(raw_error_code::insufficient_buffer);
+ if (Offset > Data->getLength() - Buffer.size())
+ return make_error<RawError>(raw_error_code::insufficient_buffer);
+
+ uint32_t BytesLeft = Buffer.size();
+ uint32_t BytesWritten = 0;
+ uint8_t *WriteBuffer = Buffer.data();
+ auto BlockList = Data->getStreamBlocks();
+ while (BytesLeft > 0) {
+ uint32_t StreamBlockAddr = BlockList[BlockNum];
+
+ auto Result = Pdb.getBlockData(StreamBlockAddr, Pdb.getBlockSize());
+ if (!Result)
+ return Result.takeError();
+
+ auto Data = *Result;
+ const uint8_t *ChunkStart = Data.data() + OffsetInBlock;
+ uint32_t BytesInChunk =
+ std::min(BytesLeft, Pdb.getBlockSize() - OffsetInBlock);
+ ::memcpy(WriteBuffer + BytesWritten, ChunkStart, BytesInChunk);
+
+ BytesWritten += BytesInChunk;
+ BytesLeft -= BytesInChunk;
+ ++BlockNum;
+ OffsetInBlock = 0;
+ }
+
+ return Error::success();
+}
+
+Error MappedBlockStream::writeBytes(uint32_t Offset,
+ ArrayRef<uint8_t> Buffer) const {
+ // Make sure we aren't trying to write beyond the end of the stream.
+ if (Buffer.size() > Data->getLength())
+ return make_error<RawError>(raw_error_code::insufficient_buffer);
+
+ if (Offset > Data->getLength() - Buffer.size())
+ return make_error<RawError>(raw_error_code::insufficient_buffer);
+
+ uint32_t BlockNum = Offset / Pdb.getBlockSize();
+ uint32_t OffsetInBlock = Offset % Pdb.getBlockSize();
+
+ uint32_t BytesLeft = Buffer.size();
+ auto BlockList = Data->getStreamBlocks();
+ uint32_t BytesWritten = 0;
+ while (BytesLeft > 0) {
+ uint32_t StreamBlockAddr = BlockList[BlockNum];
+ uint32_t BytesToWriteInChunk =
+ std::min(BytesLeft, Pdb.getBlockSize() - OffsetInBlock);
+
+ const uint8_t *Chunk = Buffer.data() + BytesWritten;
+ ArrayRef<uint8_t> ChunkData(Chunk, BytesToWriteInChunk);
+ if (auto EC = Pdb.setBlockData(StreamBlockAddr, OffsetInBlock, ChunkData))
+ return EC;
+
+ BytesLeft -= BytesToWriteInChunk;
+ BytesWritten += BytesToWriteInChunk;
+ ++BlockNum;
+ OffsetInBlock = 0;
+ }
+
+ // If this write overlapped a read which previously came from the pool,
+ // someone may still be holding a pointer to that alloc which is now invalid.
+ // Compute the overlapping range and update the cache entry, so any
+ // outstanding buffers are automatically updated.
+ for (const auto &MapEntry : CacheMap) {
+ // If the end of the written extent precedes the beginning of the cached
+ // extent, ignore this map entry.
+ if (Offset + BytesWritten < MapEntry.first)
+ continue;
+ for (const auto &Alloc : MapEntry.second) {
+ // If the end of the cached extent precedes the beginning of the written
+ // extent, ignore this alloc.
+ if (MapEntry.first + Alloc.size() < Offset)
+ continue;
+
+ // If we get here, they are guaranteed to overlap.
+ Interval WriteInterval = std::make_pair(Offset, Offset + BytesWritten);
+ Interval CachedInterval =
+ std::make_pair(MapEntry.first, MapEntry.first + Alloc.size());
+ // If they overlap, we need to write the new data into the overlapping
+ // range.
+ auto Intersection = intersect(WriteInterval, CachedInterval);
+ assert(Intersection.first <= Intersection.second);
+
+ uint32_t Length = Intersection.second - Intersection.first;
+ uint32_t SrcOffset =
+ AbsoluteDifference(WriteInterval.first, Intersection.first);
+ uint32_t DestOffset =
+ AbsoluteDifference(CachedInterval.first, Intersection.first);
+ ::memcpy(Alloc.data() + DestOffset, Buffer.data() + SrcOffset, Length);
+ }
+ }
+
+ return Error::success();
+}
+
+uint32_t MappedBlockStream::getNumBytesCopied() const {
+ return static_cast<uint32_t>(Pool.getBytesAllocated());
+}
+
+Expected<std::unique_ptr<MappedBlockStream>>
+MappedBlockStream::createIndexedStream(uint32_t StreamIdx,
+ const IPDBFile &File) {
+ if (StreamIdx >= File.getNumStreams())
+ return make_error<RawError>(raw_error_code::no_stream);
+
+ auto Data = llvm::make_unique<IndexedStreamData>(StreamIdx, File);
+ return llvm::make_unique<MappedBlockStreamImpl>(std::move(Data), File);
+}
+
+Expected<std::unique_ptr<MappedBlockStream>>
+MappedBlockStream::createDirectoryStream(const PDBFile &File) {
+ auto Data = llvm::make_unique<DirectoryStreamData>(File);
+ return llvm::make_unique<MappedBlockStreamImpl>(std::move(Data), File);
+}
diff --git a/lib/DebugInfo/PDB/Raw/ModInfo.cpp b/lib/DebugInfo/PDB/Raw/ModInfo.cpp
new file mode 100644
index 000000000000..bae135f77bc0
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/ModInfo.cpp
@@ -0,0 +1,127 @@
+//===- ModInfo.cpp - PDB module information -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
+
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+using namespace llvm::support;
+
+namespace {
+
+struct SCBytes {
+ ulittle16_t Section;
+ char Padding1[2];
+ little32_t Offset;
+ little32_t Size;
+ ulittle32_t Characteristics;
+ ulittle16_t ModuleIndex;
+ char Padding2[2];
+ ulittle32_t DataCrc;
+ ulittle32_t RelocCrc;
+};
+
+// struct Flags {
+// uint16_t fWritten : 1; // True if ModInfo is dirty
+// uint16_t fECEnabled : 1; // Is EC symbolic info present? (What is EC?)
+// uint16_t unused : 6; // Reserved
+// uint16_t iTSM : 8; // Type Server Index for this module
+//};
+const uint16_t HasECFlagMask = 0x2;
+
+const uint16_t TypeServerIndexMask = 0xFF00;
+const uint16_t TypeServerIndexShift = 8;
+}
+
+struct ModInfo::FileLayout {
+ ulittle32_t Mod; // Currently opened module. This field is a
+ // pointer in the reference implementation, but
+ // that won't work on 64-bit systems, and anyway
+ // it doesn't make sense to read a pointer from a
+ // file. For now it is unused, so just ignore it.
+ SCBytes SC; // First section contribution of this module.
+ ulittle16_t Flags; // See Flags definition.
+ ulittle16_t ModDiStream; // Stream Number of module debug info
+ ulittle32_t SymBytes; // Size of local symbol debug info in above stream
+ ulittle32_t LineBytes; // Size of line number debug info in above stream
+ ulittle32_t C13Bytes; // Size of C13 line number info in above stream
+ ulittle16_t NumFiles; // Number of files contributing to this module
+ char Padding1[2]; // Padding so the next field is 4-byte aligned.
+ ulittle32_t FileNameOffs; // array of [0..NumFiles) DBI name buffer offsets.
+ // This field is a pointer in the reference
+ // implementation, but as with `Mod`, we ignore it
+ // for now since it is unused.
+ ulittle32_t SrcFileNameNI; // Name Index for src file name
+ ulittle32_t PdbFilePathNI; // Name Index for path to compiler PDB
+ // Null terminated Module name
+ // Null terminated Obj File Name
+};
+
+ModInfo::ModInfo() : Layout(nullptr) {}
+
+ModInfo::ModInfo(const ModInfo &Info)
+ : ModuleName(Info.ModuleName), ObjFileName(Info.ObjFileName),
+ Layout(Info.Layout) {}
+
+ModInfo::~ModInfo() {}
+
+Error ModInfo::initialize(codeview::StreamRef Stream, ModInfo &Info) {
+ codeview::StreamReader Reader(Stream);
+ if (auto EC = Reader.readObject(Info.Layout))
+ return EC;
+
+ if (auto EC = Reader.readZeroString(Info.ModuleName))
+ return EC;
+
+ if (auto EC = Reader.readZeroString(Info.ObjFileName))
+ return EC;
+ return Error::success();
+}
+
+bool ModInfo::hasECInfo() const { return (Layout->Flags & HasECFlagMask) != 0; }
+
+uint16_t ModInfo::getTypeServerIndex() const {
+ return (Layout->Flags & TypeServerIndexMask) >> TypeServerIndexShift;
+}
+
+uint16_t ModInfo::getModuleStreamIndex() const { return Layout->ModDiStream; }
+
+uint32_t ModInfo::getSymbolDebugInfoByteSize() const {
+ return Layout->SymBytes;
+}
+
+uint32_t ModInfo::getLineInfoByteSize() const { return Layout->LineBytes; }
+
+uint32_t ModInfo::getC13LineInfoByteSize() const { return Layout->C13Bytes; }
+
+uint32_t ModInfo::getNumberOfFiles() const { return Layout->NumFiles; }
+
+uint32_t ModInfo::getSourceFileNameIndex() const {
+ return Layout->SrcFileNameNI;
+}
+
+uint32_t ModInfo::getPdbFilePathNameIndex() const {
+ return Layout->PdbFilePathNI;
+}
+
+StringRef ModInfo::getModuleName() const { return ModuleName; }
+
+StringRef ModInfo::getObjFileName() const { return ObjFileName; }
+
+uint32_t ModInfo::getRecordLength() const {
+ uint32_t M = ModuleName.str().size() + 1;
+ uint32_t O = ObjFileName.str().size() + 1;
+ uint32_t Size = sizeof(FileLayout) + M + O;
+ Size = llvm::alignTo(Size, 4);
+ return Size;
+}
diff --git a/lib/DebugInfo/PDB/Raw/ModStream.cpp b/lib/DebugInfo/PDB/Raw/ModStream.cpp
new file mode 100644
index 000000000000..3415fcd47790
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/ModStream.cpp
@@ -0,0 +1,82 @@
+//===- ModStream.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/ModStream.h"
+
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
+#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
+#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+ModStream::ModStream(const ModInfo &Module,
+ std::unique_ptr<MappedBlockStream> Stream)
+ : Mod(Module), Stream(std::move(Stream)) {}
+
+ModStream::~ModStream() {}
+
+Error ModStream::reload() {
+ codeview::StreamReader Reader(*Stream);
+
+ uint32_t SymbolSize = Mod.getSymbolDebugInfoByteSize();
+ uint32_t C11Size = Mod.getLineInfoByteSize();
+ uint32_t C13Size = Mod.getC13LineInfoByteSize();
+
+ if (C11Size > 0 && C13Size > 0)
+ return llvm::make_error<RawError>(raw_error_code::corrupt_file,
+ "Module has both C11 and C13 line info");
+
+ codeview::StreamRef S;
+
+ uint32_t SymbolSubstreamSig = 0;
+ if (auto EC = Reader.readInteger(SymbolSubstreamSig))
+ return EC;
+ if (auto EC = Reader.readArray(SymbolsSubstream, SymbolSize - 4))
+ return EC;
+
+ if (auto EC = Reader.readStreamRef(LinesSubstream, C11Size))
+ return EC;
+ if (auto EC = Reader.readStreamRef(C13LinesSubstream, C13Size))
+ return EC;
+
+ codeview::StreamReader LineReader(C13LinesSubstream);
+ if (auto EC = LineReader.readArray(LineInfo, LineReader.bytesRemaining()))
+ return EC;
+
+ uint32_t GlobalRefsSize;
+ if (auto EC = Reader.readInteger(GlobalRefsSize))
+ return EC;
+ if (auto EC = Reader.readStreamRef(GlobalRefsSubstream, GlobalRefsSize))
+ return EC;
+ if (Reader.bytesRemaining() > 0)
+ return llvm::make_error<RawError>(raw_error_code::corrupt_file,
+ "Unexpected bytes in module stream.");
+
+ return Error::success();
+}
+
+iterator_range<codeview::CVSymbolArray::Iterator>
+ModStream::symbols(bool *HadError) const {
+ // It's OK if the stream is empty.
+ if (SymbolsSubstream.getUnderlyingStream().getLength() == 0)
+ return llvm::make_range(SymbolsSubstream.end(), SymbolsSubstream.end());
+ return llvm::make_range(SymbolsSubstream.begin(HadError),
+ SymbolsSubstream.end());
+}
+
+iterator_range<codeview::ModuleSubstreamArray::Iterator>
+ModStream::lines(bool *HadError) const {
+ return llvm::make_range(LineInfo.begin(HadError), LineInfo.end());
+}
+
+Error ModStream::commit() { return Error::success(); }
diff --git a/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp b/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp
new file mode 100644
index 000000000000..16b086bdaa98
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp
@@ -0,0 +1,279 @@
+//===- MSFBuilder.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/MsfBuilder.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+using namespace llvm::pdb::msf;
+using namespace llvm::support;
+
+namespace {
+const uint32_t kSuperBlockBlock = 0;
+const uint32_t kFreePageMap0Block = 1;
+const uint32_t kFreePageMap1Block = 2;
+const uint32_t kNumReservedPages = 3;
+
+const uint32_t kDefaultBlockMapAddr = kNumReservedPages;
+}
+
+MsfBuilder::MsfBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow,
+ BumpPtrAllocator &Allocator)
+ : Allocator(Allocator), IsGrowable(CanGrow), BlockSize(BlockSize),
+ MininumBlocks(MinBlockCount), BlockMapAddr(kDefaultBlockMapAddr),
+ FreeBlocks(MinBlockCount, true) {
+ FreeBlocks[kSuperBlockBlock] = false;
+ FreeBlocks[kFreePageMap0Block] = false;
+ FreeBlocks[kFreePageMap1Block] = false;
+ FreeBlocks[BlockMapAddr] = false;
+}
+
+Expected<MsfBuilder> MsfBuilder::create(BumpPtrAllocator &Allocator,
+ uint32_t BlockSize,
+ uint32_t MinBlockCount, bool CanGrow) {
+ if (!msf::isValidBlockSize(BlockSize))
+ return make_error<RawError>(raw_error_code::unspecified,
+ "The requested block size is unsupported");
+
+ return MsfBuilder(BlockSize,
+ std::max(MinBlockCount, msf::getMinimumBlockCount()),
+ CanGrow, Allocator);
+}
+
+Error MsfBuilder::setBlockMapAddr(uint32_t Addr) {
+ if (Addr == BlockMapAddr)
+ return Error::success();
+
+ if (Addr >= FreeBlocks.size()) {
+ if (!IsGrowable)
+ return make_error<RawError>(raw_error_code::unspecified,
+ "Cannot grow the number of blocks");
+ FreeBlocks.resize(Addr + 1);
+ }
+
+ if (!isBlockFree(Addr))
+ return make_error<RawError>(raw_error_code::unspecified,
+ "Attempt to reuse an allocated block");
+ FreeBlocks[BlockMapAddr] = true;
+ FreeBlocks[Addr] = false;
+ BlockMapAddr = Addr;
+ return Error::success();
+}
+
+void MsfBuilder::setFreePageMap(uint32_t Fpm) { FreePageMap = Fpm; }
+
+void MsfBuilder::setUnknown1(uint32_t Unk1) { Unknown1 = Unk1; }
+
+Error MsfBuilder::setDirectoryBlocksHint(ArrayRef<uint32_t> DirBlocks) {
+ for (auto B : DirectoryBlocks)
+ FreeBlocks[B] = true;
+ for (auto B : DirBlocks) {
+ if (!isBlockFree(B)) {
+ return make_error<RawError>(raw_error_code::unspecified,
+ "Attempt to reuse an allocated block");
+ }
+ FreeBlocks[B] = false;
+ }
+
+ DirectoryBlocks = DirBlocks;
+ return Error::success();
+}
+
+Error MsfBuilder::allocateBlocks(uint32_t NumBlocks,
+ MutableArrayRef<uint32_t> Blocks) {
+ if (NumBlocks == 0)
+ return Error::success();
+
+ uint32_t NumFreeBlocks = FreeBlocks.count();
+ if (NumFreeBlocks < NumBlocks) {
+ if (!IsGrowable)
+ return make_error<RawError>(raw_error_code::unspecified,
+ "There are no free Blocks in the file");
+ uint32_t AllocBlocks = NumBlocks - NumFreeBlocks;
+ FreeBlocks.resize(AllocBlocks + FreeBlocks.size(), true);
+ }
+
+ int I = 0;
+ int Block = FreeBlocks.find_first();
+ do {
+ assert(Block != -1 && "We ran out of Blocks!");
+
+ uint32_t NextBlock = static_cast<uint32_t>(Block);
+ Blocks[I++] = NextBlock;
+ FreeBlocks.reset(NextBlock);
+ Block = FreeBlocks.find_next(Block);
+ } while (--NumBlocks > 0);
+ return Error::success();
+}
+
+uint32_t MsfBuilder::getNumUsedBlocks() const {
+ return getTotalBlockCount() - getNumFreeBlocks();
+}
+
+uint32_t MsfBuilder::getNumFreeBlocks() const { return FreeBlocks.count(); }
+
+uint32_t MsfBuilder::getTotalBlockCount() const { return FreeBlocks.size(); }
+
+bool MsfBuilder::isBlockFree(uint32_t Idx) const { return FreeBlocks[Idx]; }
+
+Error MsfBuilder::addStream(uint32_t Size, ArrayRef<uint32_t> Blocks) {
+ // Add a new stream mapped to the specified blocks. Verify that the specified
+ // blocks are both necessary and sufficient for holding the requested number
+ // of bytes, and verify that all requested blocks are free.
+ uint32_t ReqBlocks = bytesToBlocks(Size, BlockSize);
+ if (ReqBlocks != Blocks.size())
+ return make_error<RawError>(
+ raw_error_code::unspecified,
+ "Incorrect number of blocks for requested stream size");
+ for (auto Block : Blocks) {
+ if (Block >= FreeBlocks.size())
+ FreeBlocks.resize(Block + 1, true);
+
+ if (!FreeBlocks.test(Block))
+ return make_error<RawError>(
+ raw_error_code::unspecified,
+ "Attempt to re-use an already allocated block");
+ }
+ // Mark all the blocks occupied by the new stream as not free.
+ for (auto Block : Blocks) {
+ FreeBlocks.reset(Block);
+ }
+ StreamData.push_back(std::make_pair(Size, Blocks));
+ return Error::success();
+}
+
+Error MsfBuilder::addStream(uint32_t Size) {
+ uint32_t ReqBlocks = bytesToBlocks(Size, BlockSize);
+ std::vector<uint32_t> NewBlocks;
+ NewBlocks.resize(ReqBlocks);
+ if (auto EC = allocateBlocks(ReqBlocks, NewBlocks))
+ return EC;
+ StreamData.push_back(std::make_pair(Size, NewBlocks));
+ return Error::success();
+}
+
+Error MsfBuilder::setStreamSize(uint32_t Idx, uint32_t Size) {
+ uint32_t OldSize = getStreamSize(Idx);
+ if (OldSize == Size)
+ return Error::success();
+
+ uint32_t NewBlocks = bytesToBlocks(Size, BlockSize);
+ uint32_t OldBlocks = bytesToBlocks(OldSize, BlockSize);
+
+ if (NewBlocks > OldBlocks) {
+ uint32_t AddedBlocks = NewBlocks - OldBlocks;
+ // If we're growing, we have to allocate new Blocks.
+ std::vector<uint32_t> AddedBlockList;
+ AddedBlockList.resize(AddedBlocks);
+ if (auto EC = allocateBlocks(AddedBlocks, AddedBlockList))
+ return EC;
+ auto &CurrentBlocks = StreamData[Idx].second;
+ CurrentBlocks.insert(CurrentBlocks.end(), AddedBlockList.begin(),
+ AddedBlockList.end());
+ } else if (OldBlocks > NewBlocks) {
+ // For shrinking, free all the Blocks in the Block map, update the stream
+ // data, then shrink the directory.
+ uint32_t RemovedBlocks = OldBlocks - NewBlocks;
+ auto CurrentBlocks = ArrayRef<uint32_t>(StreamData[Idx].second);
+ auto RemovedBlockList = CurrentBlocks.drop_front(NewBlocks);
+ for (auto P : RemovedBlockList)
+ FreeBlocks[P] = true;
+ StreamData[Idx].second = CurrentBlocks.drop_back(RemovedBlocks);
+ }
+
+ StreamData[Idx].first = Size;
+ return Error::success();
+}
+
+uint32_t MsfBuilder::getNumStreams() const { return StreamData.size(); }
+
+uint32_t MsfBuilder::getStreamSize(uint32_t StreamIdx) const {
+ return StreamData[StreamIdx].first;
+}
+
+ArrayRef<uint32_t> MsfBuilder::getStreamBlocks(uint32_t StreamIdx) const {
+ return StreamData[StreamIdx].second;
+}
+
+uint32_t MsfBuilder::computeDirectoryByteSize() const {
+ // The directory has the following layout, where each item is a ulittle32_t:
+ // NumStreams
+ // StreamSizes[NumStreams]
+ // StreamBlocks[NumStreams][]
+ uint32_t Size = sizeof(ulittle32_t); // NumStreams
+ Size += StreamData.size() * sizeof(ulittle32_t); // StreamSizes
+ for (const auto &D : StreamData) {
+ uint32_t ExpectedNumBlocks = bytesToBlocks(D.first, BlockSize);
+ assert(ExpectedNumBlocks == D.second.size() &&
+ "Unexpected number of blocks");
+ Size += ExpectedNumBlocks * sizeof(ulittle32_t);
+ }
+ return Size;
+}
+
+Expected<Layout> MsfBuilder::build() {
+ Layout L;
+ L.SB = Allocator.Allocate<SuperBlock>();
+ std::memcpy(L.SB->MagicBytes, Magic, sizeof(Magic));
+ L.SB->BlockMapAddr = BlockMapAddr;
+ L.SB->BlockSize = BlockSize;
+ L.SB->NumDirectoryBytes = computeDirectoryByteSize();
+ L.SB->FreeBlockMapBlock = FreePageMap;
+ L.SB->Unknown1 = Unknown1;
+
+ uint32_t NumDirectoryBlocks =
+ bytesToBlocks(L.SB->NumDirectoryBytes, BlockSize);
+ if (NumDirectoryBlocks > DirectoryBlocks.size()) {
+ // Our hint wasn't enough to satisfy the entire directory. Allocate
+ // remaining pages.
+ std::vector<uint32_t> ExtraBlocks;
+ uint32_t NumExtraBlocks = NumDirectoryBlocks - DirectoryBlocks.size();
+ ExtraBlocks.resize(NumExtraBlocks);
+ if (auto EC = allocateBlocks(NumExtraBlocks, ExtraBlocks))
+ return std::move(EC);
+ DirectoryBlocks.insert(DirectoryBlocks.end(), ExtraBlocks.begin(),
+ ExtraBlocks.end());
+ } else if (NumDirectoryBlocks < DirectoryBlocks.size()) {
+ uint32_t NumUnnecessaryBlocks = DirectoryBlocks.size() - NumDirectoryBlocks;
+ for (auto B :
+ ArrayRef<uint32_t>(DirectoryBlocks).drop_back(NumUnnecessaryBlocks))
+ FreeBlocks[B] = true;
+ DirectoryBlocks.resize(NumDirectoryBlocks);
+ }
+
+ // Don't set the number of blocks in the file until after allocating Blocks
+ // for
+ // the directory, since the allocation might cause the file to need to grow.
+ L.SB->NumBlocks = FreeBlocks.size();
+
+ ulittle32_t *DirBlocks = Allocator.Allocate<ulittle32_t>(NumDirectoryBlocks);
+ std::uninitialized_copy_n(DirectoryBlocks.begin(), NumDirectoryBlocks,
+ DirBlocks);
+ L.DirectoryBlocks = ArrayRef<ulittle32_t>(DirBlocks, NumDirectoryBlocks);
+
+ // The stream sizes should be re-allocated as a stable pointer and the stream
+ // map should have each of its entries allocated as a separate stable pointer.
+ if (StreamData.size() > 0) {
+ ulittle32_t *Sizes = Allocator.Allocate<ulittle32_t>(StreamData.size());
+ L.StreamSizes = ArrayRef<ulittle32_t>(Sizes, StreamData.size());
+ L.StreamMap.resize(StreamData.size());
+ for (uint32_t I = 0; I < StreamData.size(); ++I) {
+ Sizes[I] = StreamData[I].first;
+ ulittle32_t *BlockList =
+ Allocator.Allocate<ulittle32_t>(StreamData[I].second.size());
+ std::uninitialized_copy_n(StreamData[I].second.begin(),
+ StreamData[I].second.size(), BlockList);
+ L.StreamMap[I] =
+ ArrayRef<ulittle32_t>(BlockList, StreamData[I].second.size());
+ }
+ }
+
+ return L;
+}
diff --git a/lib/DebugInfo/PDB/Raw/MsfCommon.cpp b/lib/DebugInfo/PDB/Raw/MsfCommon.cpp
new file mode 100644
index 000000000000..5d97f33e1103
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/MsfCommon.cpp
@@ -0,0 +1,48 @@
+//===- MsfCommon.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/MsfCommon.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+
+using namespace llvm;
+using namespace llvm::pdb::msf;
+
+Error llvm::pdb::msf::validateSuperBlock(const SuperBlock &SB) {
+ // Check the magic bytes.
+ if (std::memcmp(SB.MagicBytes, Magic, sizeof(Magic)) != 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "MSF magic header doesn't match");
+
+ if (!isValidBlockSize(SB.BlockSize))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Unsupported block size.");
+
+ // We don't support directories whose sizes aren't a multiple of four bytes.
+ if (SB.NumDirectoryBytes % sizeof(support::ulittle32_t) != 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Directory size is not multiple of 4.");
+
+ // The number of blocks which comprise the directory is a simple function of
+ // the number of bytes it contains.
+ uint64_t NumDirectoryBlocks =
+ bytesToBlocks(SB.NumDirectoryBytes, SB.BlockSize);
+
+ // The directory, as we understand it, is a block which consists of a list of
+ // block numbers. It is unclear what would happen if the number of blocks
+ // couldn't fit on a single block.
+ if (NumDirectoryBlocks > SB.BlockSize / sizeof(support::ulittle32_t))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Too many directory blocks.");
+
+ if (SB.BlockMapAddr == 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Block 0 is reserved");
+
+ return Error::success();
+}
diff --git a/lib/DebugInfo/PDB/Raw/NameHashTable.cpp b/lib/DebugInfo/PDB/Raw/NameHashTable.cpp
new file mode 100644
index 000000000000..ae4ebf27721e
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/NameHashTable.cpp
@@ -0,0 +1,104 @@
+//===- NameHashTable.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/PDB/Raw/Hash.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support;
+using namespace llvm::pdb;
+
+NameHashTable::NameHashTable() : Signature(0), HashVersion(0), NameCount(0) {}
+
+Error NameHashTable::load(codeview::StreamReader &Stream) {
+ struct Header {
+ support::ulittle32_t Signature;
+ support::ulittle32_t HashVersion;
+ support::ulittle32_t ByteSize;
+ };
+
+ const Header *H;
+ if (auto EC = Stream.readObject(H))
+ return EC;
+
+ if (H->Signature != 0xEFFEEFFE)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid hash table signature");
+ if (H->HashVersion != 1 && H->HashVersion != 2)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Unsupported hash version");
+
+ Signature = H->Signature;
+ HashVersion = H->HashVersion;
+ if (auto EC = Stream.readStreamRef(NamesBuffer, H->ByteSize))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid hash table byte length"));
+
+ const support::ulittle32_t *HashCount;
+ if (auto EC = Stream.readObject(HashCount))
+ return EC;
+
+ if (auto EC = Stream.readArray(IDs, *HashCount))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read bucket array"));
+
+ if (Stream.bytesRemaining() < sizeof(support::ulittle32_t))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Missing name count");
+
+ if (auto EC = Stream.readInteger(NameCount))
+ return EC;
+ return Error::success();
+}
+
+StringRef NameHashTable::getStringForID(uint32_t ID) const {
+ if (ID == IDs[0])
+ return StringRef();
+
+ // NamesBuffer is a buffer of null terminated strings back to back. ID is
+ // the starting offset of the string we're looking for. So just seek into
+ // the desired offset and a read a null terminated stream from that offset.
+ StringRef Result;
+ codeview::StreamReader NameReader(NamesBuffer);
+ NameReader.setOffset(ID);
+ if (auto EC = NameReader.readZeroString(Result))
+ consumeError(std::move(EC));
+ return Result;
+}
+
+uint32_t NameHashTable::getIDForString(StringRef Str) const {
+ uint32_t Hash = (HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
+ size_t Count = IDs.size();
+ uint32_t Start = Hash % Count;
+ for (size_t I = 0; I < Count; ++I) {
+ // The hash is just a starting point for the search, but if it
+ // doesn't work we should find the string no matter what, because
+ // we iterate the entire array.
+ uint32_t Index = (Start + I) % Count;
+
+ uint32_t ID = IDs[Index];
+ StringRef S = getStringForID(ID);
+ if (S == Str)
+ return ID;
+ }
+ // IDs[0] contains the ID of the "invalid" entry.
+ return IDs[0];
+}
+
+codeview::FixedStreamArray<support::ulittle32_t>
+NameHashTable::name_ids() const {
+ return IDs;
+}
diff --git a/lib/DebugInfo/PDB/Raw/NameMap.cpp b/lib/DebugInfo/PDB/Raw/NameMap.cpp
new file mode 100644
index 000000000000..b8a4eb79a48c
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/NameMap.cpp
@@ -0,0 +1,213 @@
+//===- NameMap.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/NameMap.h"
+#include "llvm/ADT/SparseBitVector.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/CodeView/StreamWriter.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+NameMap::NameMap() {}
+
+Error NameMap::load(codeview::StreamReader &Stream) {
+
+ // This is some sort of weird string-set/hash table encoded in the stream.
+ // It starts with the number of bytes in the table.
+ uint32_t NumberOfBytes;
+ if (auto EC = Stream.readInteger(NumberOfBytes))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Expected name map length"));
+ if (Stream.bytesRemaining() < NumberOfBytes)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid name map length");
+
+ // Following that field is the starting offset of strings in the name table.
+ uint32_t StringsOffset = Stream.getOffset();
+ Stream.setOffset(StringsOffset + NumberOfBytes);
+
+ // This appears to be equivalent to the total number of strings *actually*
+ // in the name table.
+ uint32_t HashSize;
+ if (auto EC = Stream.readInteger(HashSize))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Expected name map hash size"));
+
+ // This appears to be an upper bound on the number of strings in the name
+ // table.
+ uint32_t MaxNumberOfStrings;
+ if (auto EC = Stream.readInteger(MaxNumberOfStrings))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Expected name map max strings"));
+
+ if (MaxNumberOfStrings > (UINT32_MAX / sizeof(uint32_t)))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Implausible number of strings");
+
+ const uint32_t MaxNumberOfWords = UINT32_MAX / (sizeof(uint32_t) * 8);
+
+ // This appears to be a hash table which uses bitfields to determine whether
+ // or not a bucket is 'present'.
+ uint32_t NumPresentWords;
+ if (auto EC = Stream.readInteger(NumPresentWords))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Expected name map num words"));
+
+ if (NumPresentWords > MaxNumberOfWords)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Number of present words is too large");
+
+ SparseBitVector<> Present;
+ for (uint32_t I = 0; I != NumPresentWords; ++I) {
+ uint32_t Word;
+ if (auto EC = Stream.readInteger(Word))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Expected name map word"));
+ for (unsigned Idx = 0; Idx < 32; ++Idx)
+ if (Word & (1U << Idx))
+ Present.set((I * 32) + Idx);
+ }
+
+ // This appears to be a hash table which uses bitfields to determine whether
+ // or not a bucket is 'deleted'.
+ uint32_t NumDeletedWords;
+ if (auto EC = Stream.readInteger(NumDeletedWords))
+ return joinErrors(
+ std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Expected name map num deleted words"));
+
+ if (NumDeletedWords > MaxNumberOfWords)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Number of deleted words is too large");
+
+ SparseBitVector<> Deleted;
+ for (uint32_t I = 0; I != NumDeletedWords; ++I) {
+ uint32_t Word;
+ if (auto EC = Stream.readInteger(Word))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Expected name map word"));
+ for (unsigned Idx = 0; Idx < 32; ++Idx)
+ if (Word & (1U << Idx))
+ Deleted.set((I * 32) + Idx);
+ }
+
+ for (unsigned I : Present) {
+ // For all present entries, dump out their mapping.
+ (void)I;
+
+ // This appears to be an offset relative to the start of the strings.
+ // It tells us where the null-terminated string begins.
+ uint32_t NameOffset;
+ if (auto EC = Stream.readInteger(NameOffset))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Expected name map name offset"));
+
+ // This appears to be a stream number into the stream directory.
+ uint32_t NameIndex;
+ if (auto EC = Stream.readInteger(NameIndex))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Expected name map name index"));
+
+ // Compute the offset of the start of the string relative to the stream.
+ uint32_t StringOffset = StringsOffset + NameOffset;
+ uint32_t OldOffset = Stream.getOffset();
+ // Pump out our c-string from the stream.
+ StringRef Str;
+ Stream.setOffset(StringOffset);
+ if (auto EC = Stream.readZeroString(Str))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Expected name map name"));
+
+ Stream.setOffset(OldOffset);
+ // Add this to a string-map from name to stream number.
+ Mapping.insert({Str, NameIndex});
+ }
+
+ return Error::success();
+}
+
+Error NameMap::commit(codeview::StreamWriter &Writer) {
+ // The first field is the number of bytes of string data. So add
+ // up the length of all strings plus a null terminator for each
+ // one.
+ uint32_t NumBytes = 0;
+ for (auto B = Mapping.begin(), E = Mapping.end(); B != E; ++B) {
+ NumBytes += B->getKeyLength() + 1;
+ }
+
+ if (auto EC = Writer.writeInteger(NumBytes)) // Number of bytes of string data
+ return EC;
+ // Now all of the string data itself.
+ for (auto B = Mapping.begin(), E = Mapping.end(); B != E; ++B) {
+ if (auto EC = Writer.writeZeroString(B->getKey()))
+ return EC;
+ }
+
+ if (auto EC = Writer.writeInteger(Mapping.size())) // Hash Size
+ return EC;
+
+ if (auto EC = Writer.writeInteger(Mapping.size())) // Max Number of Strings
+ return EC;
+
+ if (auto EC = Writer.writeInteger(Mapping.size())) // Num Present Words
+ return EC;
+
+ // For each entry in the mapping, write a bit mask which represents a bucket
+ // to store it in. We don't use this, so the value we write isn't important
+ // to us, it just has to be there.
+ for (auto B = Mapping.begin(), E = Mapping.end(); B != E; ++B) {
+ if (auto EC = Writer.writeInteger(1U))
+ return EC;
+ }
+
+ if (auto EC = Writer.writeInteger(0U)) // Num Deleted Words
+ return EC;
+
+ // Mappings of each word.
+ uint32_t OffsetSoFar = 0;
+ for (auto B = Mapping.begin(), E = Mapping.end(); B != E; ++B) {
+ // This is a list of key value pairs where the key is the offset into the
+ // strings buffer, and the value is a stream number. Write each pair.
+ if (auto EC = Writer.writeInteger(OffsetSoFar))
+ return EC;
+
+ if (auto EC = Writer.writeInteger(B->second))
+ return EC;
+
+ OffsetSoFar += B->getKeyLength() + 1;
+ }
+
+ return Error::success();
+}
+
+iterator_range<StringMapConstIterator<uint32_t>> NameMap::entries() const {
+ return llvm::make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
+ Mapping.end());
+}
+
+bool NameMap::tryGetValue(StringRef Name, uint32_t &Value) const {
+ auto Iter = Mapping.find(Name);
+ if (Iter == Mapping.end())
+ return false;
+ Value = Iter->second;
+ return true;
+}
diff --git a/lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp b/lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp
new file mode 100644
index 000000000000..41c6c2cd810a
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp
@@ -0,0 +1,50 @@
+//===- NameMapBuilder.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/NameMapBuilder.h"
+
+#include "llvm/DebugInfo/PDB/Raw/NameMap.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+NameMapBuilder::NameMapBuilder() {}
+
+void NameMapBuilder::addMapping(StringRef Name, uint32_t Mapping) {
+ StringDataBytes += Name.size() + 1;
+ Map.insert({Name, Mapping});
+}
+
+Expected<std::unique_ptr<NameMap>> NameMapBuilder::build() {
+ auto Result = llvm::make_unique<NameMap>();
+ Result->Mapping = Map;
+ return std::move(Result);
+}
+
+uint32_t NameMapBuilder::calculateSerializedLength() const {
+ uint32_t TotalLength = 0;
+
+ TotalLength += sizeof(support::ulittle32_t); // StringDataBytes value
+ TotalLength += StringDataBytes; // actual string data
+
+ TotalLength += sizeof(support::ulittle32_t); // Hash Size
+ TotalLength += sizeof(support::ulittle32_t); // Max Number of Strings
+ TotalLength += sizeof(support::ulittle32_t); // Num Present Words
+ // One bitmask word for each present entry
+ TotalLength += Map.size() * sizeof(support::ulittle32_t);
+ TotalLength += sizeof(support::ulittle32_t); // Num Deleted Words
+
+ // For each present word, which we are treating as equivalent to the number of
+ // entries in the table, we have a pair of integers. An offset into the
+ // string data, and a corresponding stream number.
+ TotalLength += Map.size() * 2 * sizeof(support::ulittle32_t);
+
+ return TotalLength;
+}
diff --git a/lib/DebugInfo/PDB/Raw/PDBFile.cpp b/lib/DebugInfo/PDB/Raw/PDBFile.cpp
new file mode 100644
index 000000000000..95016753dc14
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/PDBFile.cpp
@@ -0,0 +1,365 @@
+//===- PDBFile.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/StreamArray.h"
+#include "llvm/DebugInfo/CodeView/StreamInterface.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/CodeView/StreamWriter.h"
+#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h"
+#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
+#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h"
+#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+namespace {
+typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
+}
+
+PDBFile::PDBFile(std::unique_ptr<StreamInterface> PdbFileBuffer)
+ : Buffer(std::move(PdbFileBuffer)), SB(nullptr) {}
+
+PDBFile::~PDBFile() {}
+
+uint32_t PDBFile::getBlockSize() const { return SB->BlockSize; }
+
+uint32_t PDBFile::getFreeBlockMapBlock() const { return SB->FreeBlockMapBlock; }
+
+uint32_t PDBFile::getBlockCount() const { return SB->NumBlocks; }
+
+uint32_t PDBFile::getNumDirectoryBytes() const { return SB->NumDirectoryBytes; }
+
+uint32_t PDBFile::getBlockMapIndex() const { return SB->BlockMapAddr; }
+
+uint32_t PDBFile::getUnknown1() const { return SB->Unknown1; }
+
+uint32_t PDBFile::getNumDirectoryBlocks() const {
+ return msf::bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize);
+}
+
+uint64_t PDBFile::getBlockMapOffset() const {
+ return (uint64_t)SB->BlockMapAddr * SB->BlockSize;
+}
+
+uint32_t PDBFile::getNumStreams() const { return StreamSizes.size(); }
+
+uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
+ return StreamSizes[StreamIndex];
+}
+
+ArrayRef<support::ulittle32_t>
+PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
+ return StreamMap[StreamIndex];
+}
+
+uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); }
+
+Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
+ uint32_t NumBytes) const {
+ uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
+
+ ArrayRef<uint8_t> Result;
+ if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
+ return std::move(EC);
+ return Result;
+}
+
+Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
+ ArrayRef<uint8_t> Data) const {
+ if (Offset >= getBlockSize())
+ return make_error<RawError>(
+ raw_error_code::invalid_block_address,
+ "setBlockData attempted to write out of block bounds.");
+ if (Data.size() > getBlockSize() - Offset)
+ return make_error<RawError>(
+ raw_error_code::invalid_block_address,
+ "setBlockData attempted to write out of block bounds.");
+
+ uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
+ StreamBlockOffset += Offset;
+ return Buffer->writeBytes(StreamBlockOffset, Data);
+}
+
+Error PDBFile::parseFileHeaders() {
+ StreamReader Reader(*Buffer);
+
+ if (auto EC = Reader.readObject(SB)) {
+ consumeError(std::move(EC));
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Does not contain superblock");
+ }
+
+ if (auto EC = setSuperBlock(SB))
+ return EC;
+
+ Reader.setOffset(getBlockMapOffset());
+ if (auto EC = Reader.readArray(DirectoryBlocks, getNumDirectoryBlocks()))
+ return EC;
+
+ return Error::success();
+}
+
+Error PDBFile::parseStreamData() {
+ assert(SB);
+ if (DirectoryStream)
+ return Error::success();
+
+ uint32_t NumStreams = 0;
+
+ // Normally you can't use a MappedBlockStream without having fully parsed the
+ // PDB file, because it accesses the directory and various other things, which
+ // is exactly what we are attempting to parse. By specifying a custom
+ // subclass of IPDBStreamData which only accesses the fields that have already
+ // been parsed, we can avoid this and reuse MappedBlockStream.
+ auto DS = MappedBlockStream::createDirectoryStream(*this);
+ if (!DS)
+ return DS.takeError();
+ StreamReader Reader(**DS);
+ if (auto EC = Reader.readInteger(NumStreams))
+ return EC;
+
+ if (auto EC = Reader.readArray(StreamSizes, NumStreams))
+ return EC;
+ for (uint32_t I = 0; I < NumStreams; ++I) {
+ uint32_t StreamSize = getStreamByteSize(I);
+ // FIXME: What does StreamSize ~0U mean?
+ uint64_t NumExpectedStreamBlocks =
+ StreamSize == UINT32_MAX ? 0 : msf::bytesToBlocks(StreamSize,
+ SB->BlockSize);
+
+ // For convenience, we store the block array contiguously. This is because
+ // if someone calls setStreamMap(), it is more convenient to be able to call
+ // it with an ArrayRef instead of setting up a StreamRef. Since the
+ // DirectoryStream is cached in the class and thus lives for the life of the
+ // class, we can be guaranteed that readArray() will return a stable
+ // reference, even if it has to allocate from its internal pool.
+ ArrayRef<support::ulittle32_t> Blocks;
+ if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
+ return EC;
+ for (uint32_t Block : Blocks) {
+ uint64_t BlockEndOffset = (uint64_t)(Block + 1) * SB->BlockSize;
+ if (BlockEndOffset > getFileSize())
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Stream block map is corrupt.");
+ }
+ StreamMap.push_back(Blocks);
+ }
+
+ // We should have read exactly SB->NumDirectoryBytes bytes.
+ assert(Reader.bytesRemaining() == 0);
+ DirectoryStream = std::move(*DS);
+ return Error::success();
+}
+
+llvm::ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
+ return DirectoryBlocks;
+}
+
+Expected<InfoStream &> PDBFile::getPDBInfoStream() {
+ if (!Info) {
+ auto InfoS = MappedBlockStream::createIndexedStream(StreamPDB, *this);
+ if (!InfoS)
+ return InfoS.takeError();
+ auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
+ if (auto EC = TempInfo->reload())
+ return std::move(EC);
+ Info = std::move(TempInfo);
+ }
+ return *Info;
+}
+
+Expected<DbiStream &> PDBFile::getPDBDbiStream() {
+ if (!Dbi) {
+ auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, *this);
+ if (!DbiS)
+ return DbiS.takeError();
+ auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS));
+ if (auto EC = TempDbi->reload())
+ return std::move(EC);
+ Dbi = std::move(TempDbi);
+ }
+ return *Dbi;
+}
+
+Expected<TpiStream &> PDBFile::getPDBTpiStream() {
+ if (!Tpi) {
+ auto TpiS = MappedBlockStream::createIndexedStream(StreamTPI, *this);
+ if (!TpiS)
+ return TpiS.takeError();
+ auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
+ if (auto EC = TempTpi->reload())
+ return std::move(EC);
+ Tpi = std::move(TempTpi);
+ }
+ return *Tpi;
+}
+
+Expected<TpiStream &> PDBFile::getPDBIpiStream() {
+ if (!Ipi) {
+ auto IpiS = MappedBlockStream::createIndexedStream(StreamIPI, *this);
+ if (!IpiS)
+ return IpiS.takeError();
+ auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
+ if (auto EC = TempIpi->reload())
+ return std::move(EC);
+ Ipi = std::move(TempIpi);
+ }
+ return *Ipi;
+}
+
+Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
+ if (!Publics) {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS)
+ return DbiS.takeError();
+
+ uint32_t PublicsStreamNum = DbiS->getPublicSymbolStreamIndex();
+
+ auto PublicS =
+ MappedBlockStream::createIndexedStream(PublicsStreamNum, *this);
+ if (!PublicS)
+ return PublicS.takeError();
+ auto TempPublics =
+ llvm::make_unique<PublicsStream>(*this, std::move(*PublicS));
+ if (auto EC = TempPublics->reload())
+ return std::move(EC);
+ Publics = std::move(TempPublics);
+ }
+ return *Publics;
+}
+
+Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
+ if (!Symbols) {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS)
+ return DbiS.takeError();
+
+ uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
+
+ auto SymbolS =
+ MappedBlockStream::createIndexedStream(SymbolStreamNum, *this);
+ if (!SymbolS)
+ return SymbolS.takeError();
+ auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
+ if (auto EC = TempSymbols->reload())
+ return std::move(EC);
+ Symbols = std::move(TempSymbols);
+ }
+ return *Symbols;
+}
+
+Expected<NameHashTable &> PDBFile::getStringTable() {
+ if (!StringTable || !StringTableStream) {
+ auto IS = getPDBInfoStream();
+ if (!IS)
+ return IS.takeError();
+
+ uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names");
+
+ if (NameStreamIndex == 0)
+ return make_error<RawError>(raw_error_code::no_stream);
+ if (NameStreamIndex >= getNumStreams())
+ return make_error<RawError>(raw_error_code::no_stream);
+
+ auto NS = MappedBlockStream::createIndexedStream(NameStreamIndex, *this);
+ if (!NS)
+ return NS.takeError();
+
+ StreamReader Reader(**NS);
+ auto N = llvm::make_unique<NameHashTable>();
+ if (auto EC = N->load(Reader))
+ return std::move(EC);
+ StringTable = std::move(N);
+ StringTableStream = std::move(*NS);
+ }
+ return *StringTable;
+}
+
+Error PDBFile::setSuperBlock(const msf::SuperBlock *Block) {
+ if (auto EC = msf::validateSuperBlock(*Block))
+ return EC;
+
+ if (Buffer->getLength() % SB->BlockSize != 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "File size is not a multiple of block size");
+
+ SB = Block;
+ return Error::success();
+}
+
+Error PDBFile::commit() {
+ StreamWriter Writer(*Buffer);
+
+ if (auto EC = Writer.writeObject(*SB))
+ return EC;
+ Writer.setOffset(getBlockMapOffset());
+ if (auto EC = Writer.writeArray(DirectoryBlocks))
+ return EC;
+
+ auto DS = MappedBlockStream::createDirectoryStream(*this);
+ if (!DS)
+ return DS.takeError();
+ auto DirStream = std::move(*DS);
+ StreamWriter DW(*DirStream);
+ if (auto EC = DW.writeInteger(this->getNumStreams()))
+ return EC;
+
+ if (auto EC = DW.writeArray(StreamSizes))
+ return EC;
+
+ for (const auto &Blocks : StreamMap) {
+ if (auto EC = DW.writeArray(Blocks))
+ return EC;
+ }
+
+ if (Info) {
+ if (auto EC = Info->commit())
+ return EC;
+ }
+
+ if (Dbi) {
+ if (auto EC = Dbi->commit())
+ return EC;
+ }
+
+ if (Symbols) {
+ if (auto EC = Symbols->commit())
+ return EC;
+ }
+
+ if (Publics) {
+ if (auto EC = Publics->commit())
+ return EC;
+ }
+
+ if (Tpi) {
+ if (auto EC = Tpi->commit())
+ return EC;
+ }
+
+ if (Ipi) {
+ if (auto EC = Ipi->commit())
+ return EC;
+ }
+
+ return Buffer->commit();
+}
diff --git a/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp b/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp
new file mode 100644
index 000000000000..9063fd62d295
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp
@@ -0,0 +1,102 @@
+//===- PDBFileBuilder.cpp - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h"
+
+#include "llvm/ADT/BitVector.h"
+
+#include "llvm/DebugInfo/CodeView/StreamInterface.h"
+#include "llvm/DebugInfo/CodeView/StreamWriter.h"
+#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+using namespace llvm::support;
+
+PDBFileBuilder::PDBFileBuilder(
+ std::unique_ptr<codeview::StreamInterface> FileBuffer)
+ : File(llvm::make_unique<PDBFile>(std::move(FileBuffer))) {}
+
+Error PDBFileBuilder::initialize(const msf::SuperBlock &Super) {
+ auto ExpectedMsf =
+ MsfBuilder::create(File->Allocator, Super.BlockSize, Super.NumBlocks);
+ if (!ExpectedMsf)
+ return ExpectedMsf.takeError();
+
+ auto &MsfResult = *ExpectedMsf;
+ if (auto EC = MsfResult.setBlockMapAddr(Super.BlockMapAddr))
+ return EC;
+ Msf = llvm::make_unique<MsfBuilder>(std::move(MsfResult));
+ Msf->setFreePageMap(Super.FreeBlockMapBlock);
+ Msf->setUnknown1(Super.Unknown1);
+ return Error::success();
+}
+
+MsfBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
+
+InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
+ if (!Info)
+ Info = llvm::make_unique<InfoStreamBuilder>();
+ return *Info;
+}
+
+DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
+ if (!Dbi)
+ Dbi = llvm::make_unique<DbiStreamBuilder>();
+ return *Dbi;
+}
+
+Expected<std::unique_ptr<PDBFile>> PDBFileBuilder::build() {
+ if (Info) {
+ uint32_t Length = Info->calculateSerializedLength();
+ if (auto EC = Msf->setStreamSize(StreamPDB, Length))
+ return std::move(EC);
+ }
+ if (Dbi) {
+ uint32_t Length = Dbi->calculateSerializedLength();
+ if (auto EC = Msf->setStreamSize(StreamDBI, Length))
+ return std::move(EC);
+ }
+
+ auto ExpectedLayout = Msf->build();
+ if (!ExpectedLayout)
+ return ExpectedLayout.takeError();
+
+ const msf::Layout &L = *ExpectedLayout;
+ File->StreamMap = L.StreamMap;
+ File->StreamSizes = L.StreamSizes;
+ File->DirectoryBlocks = L.DirectoryBlocks;
+ File->SB = L.SB;
+
+ if (Info) {
+ auto ExpectedInfo = Info->build(*File);
+ if (!ExpectedInfo)
+ return ExpectedInfo.takeError();
+ File->Info = std::move(*ExpectedInfo);
+ }
+
+ if (Dbi) {
+ auto ExpectedDbi = Dbi->build(*File);
+ if (!ExpectedDbi)
+ return ExpectedDbi.takeError();
+ File->Dbi = std::move(*ExpectedDbi);
+ }
+
+ if (File->Info && File->Dbi && File->Info->getAge() != File->Dbi->getAge())
+ return llvm::make_error<RawError>(
+ raw_error_code::corrupt_file,
+ "PDB Stream Age doesn't match Dbi Stream Age!");
+
+ return std::move(File);
+}
diff --git a/lib/DebugInfo/PDB/Raw/PublicsStream.cpp b/lib/DebugInfo/PDB/Raw/PublicsStream.cpp
new file mode 100644
index 000000000000..af3d2d026b48
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/PublicsStream.cpp
@@ -0,0 +1,173 @@
+//===- PublicsStream.cpp - PDB Public Symbol Stream -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The data structures defined in this file are based on the reference
+// implementation which is available at
+// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
+//
+// When you are reading the reference source code, you'd find the
+// information below useful.
+//
+// - ppdb1->m_fMinimalDbgInfo seems to be always true.
+// - SMALLBUCKETS macro is defined.
+//
+// The reference doesn't compile, so I learned just by reading code.
+// It's not guaranteed to be correct.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
+#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/SymbolStream.h"
+
+#include "llvm/ADT/BitVector.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MathExtras.h"
+
+using namespace llvm;
+using namespace llvm::support;
+using namespace llvm::pdb;
+
+
+static const unsigned IPHR_HASH = 4096;
+
+// This is PSGSIHDR struct defined in
+// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
+struct PublicsStream::HeaderInfo {
+ ulittle32_t SymHash;
+ ulittle32_t AddrMap;
+ ulittle32_t NumThunks;
+ ulittle32_t SizeOfThunk;
+ ulittle16_t ISectThunkTable;
+ char Padding[2];
+ ulittle32_t OffThunkTable;
+ ulittle32_t NumSections;
+};
+
+// This is GSIHashHdr.
+struct PublicsStream::GSIHashHeader {
+ enum : unsigned {
+ HdrSignature = ~0U,
+ HdrVersion = 0xeffe0000 + 19990810,
+ };
+ ulittle32_t VerSignature;
+ ulittle32_t VerHdr;
+ ulittle32_t HrSize;
+ ulittle32_t NumBuckets;
+};
+
+PublicsStream::PublicsStream(PDBFile &File,
+ std::unique_ptr<MappedBlockStream> Stream)
+ : Pdb(File), Stream(std::move(Stream)) {}
+
+PublicsStream::~PublicsStream() {}
+
+uint32_t PublicsStream::getSymHash() const { return Header->SymHash; }
+uint32_t PublicsStream::getAddrMap() const { return Header->AddrMap; }
+
+// Publics stream contains fixed-size headers and a serialized hash table.
+// This implementation is not complete yet. It reads till the end of the
+// stream so that we verify the stream is at least not corrupted. However,
+// we skip over the hash table which we believe contains information about
+// public symbols.
+Error PublicsStream::reload() {
+ codeview::StreamReader Reader(*Stream);
+
+ // Check stream size.
+ if (Reader.bytesRemaining() < sizeof(HeaderInfo) + sizeof(GSIHashHeader))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Publics Stream does not contain a header.");
+
+ // Read PSGSIHDR and GSIHashHdr structs.
+ if (Reader.readObject(Header))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Publics Stream does not contain a header.");
+
+ if (Reader.readObject(HashHdr))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Publics Stream does not contain a header.");
+
+ // An array of HashRecord follows. Read them.
+ if (HashHdr->HrSize % sizeof(PSHashRecord))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid HR array size.");
+ uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord);
+ if (auto EC = Reader.readArray(HashRecords, NumHashRecords))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read an HR array"));
+
+ // A bitmap of a fixed length follows.
+ size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32);
+ uint32_t NumBitmapEntries = BitmapSizeInBits / 8;
+ if (auto EC = Reader.readBytes(Bitmap, NumBitmapEntries))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read a bitmap."));
+ for (uint8_t B : Bitmap)
+ NumBuckets += countPopulation(B);
+
+ // We don't yet understand the following data structures completely,
+ // but we at least know the types and sizes. Here we are trying
+ // to read the stream till end so that we at least can detect
+ // corrupted streams.
+
+ // Hash buckets follow.
+ if (auto EC = Reader.readArray(HashBuckets, NumBuckets))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Hash buckets corrupted."));
+
+ // Something called "address map" follows.
+ uint32_t NumAddressMapEntries = Header->AddrMap / sizeof(uint32_t);
+ if (auto EC = Reader.readArray(AddressMap, NumAddressMapEntries))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read an address map."));
+
+ // Something called "thunk map" follows.
+ if (auto EC = Reader.readArray(ThunkMap, Header->NumThunks))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read a thunk map."));
+
+ // Something called "section map" follows.
+ if (auto EC = Reader.readArray(SectionOffsets, Header->NumSections))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read a section map."));
+
+ if (Reader.bytesRemaining() > 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Corrupted publics stream.");
+ return Error::success();
+}
+
+iterator_range<codeview::CVSymbolArray::Iterator>
+PublicsStream::getSymbols(bool *HadError) const {
+ auto SymbolS = Pdb.getPDBSymbolStream();
+ if (SymbolS.takeError()) {
+ codeview::CVSymbolArray::Iterator Iter;
+ return llvm::make_range(Iter, Iter);
+ }
+ SymbolStream &SS = SymbolS.get();
+
+ return SS.getSymbols(HadError);
+}
+
+Error PublicsStream::commit() { return Error::success(); }
diff --git a/lib/DebugInfo/PDB/Raw/RawError.cpp b/lib/DebugInfo/PDB/Raw/RawError.cpp
new file mode 100644
index 000000000000..eb169f70e11c
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/RawError.cpp
@@ -0,0 +1,67 @@
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+namespace {
+// FIXME: This class is only here to support the transition to llvm::Error. It
+// will be removed once this transition is complete. Clients should prefer to
+// deal with the Error value directly, rather than converting to error_code.
+class RawErrorCategory : public std::error_category {
+public:
+ const char *name() const LLVM_NOEXCEPT override { return "llvm.pdb.raw"; }
+
+ std::string message(int Condition) const override {
+ switch (static_cast<raw_error_code>(Condition)) {
+ case raw_error_code::unspecified:
+ return "An unknown error has occurred.";
+ case raw_error_code::feature_unsupported:
+ return "The feature is unsupported by the implementation.";
+ case raw_error_code::corrupt_file:
+ return "The PDB file is corrupt.";
+ case raw_error_code::insufficient_buffer:
+ return "The buffer is not large enough to read the requested number of "
+ "bytes.";
+ case raw_error_code::no_stream:
+ return "The specified stream could not be loaded.";
+ case raw_error_code::index_out_of_bounds:
+ return "The specified item does not exist in the array.";
+ case raw_error_code::invalid_block_address:
+ return "The specified block address is not valid.";
+ case raw_error_code::not_writable:
+ return "The PDB does not support writing.";
+ case raw_error_code::invalid_tpi_hash:
+ return "The Type record has an invalid hash value.";
+ }
+ llvm_unreachable("Unrecognized raw_error_code");
+ }
+};
+} // end anonymous namespace
+
+static ManagedStatic<RawErrorCategory> Category;
+
+char RawError::ID = 0;
+
+RawError::RawError(raw_error_code C) : RawError(C, "") {}
+
+RawError::RawError(const std::string &Context)
+ : RawError(raw_error_code::unspecified, Context) {}
+
+RawError::RawError(raw_error_code C, const std::string &Context) : Code(C) {
+ ErrMsg = "Native PDB Error: ";
+ std::error_code EC = convertToErrorCode();
+ if (Code != raw_error_code::unspecified)
+ ErrMsg += EC.message() + " ";
+ if (!Context.empty())
+ ErrMsg += Context;
+}
+
+void RawError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; }
+
+const std::string &RawError::getErrorMessage() const { return ErrMsg; }
+
+std::error_code RawError::convertToErrorCode() const {
+ return std::error_code(static_cast<int>(Code), *Category);
+}
diff --git a/lib/DebugInfo/PDB/Raw/RawSession.cpp b/lib/DebugInfo/PDB/Raw/RawSession.cpp
new file mode 100644
index 000000000000..455d33140dd4
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/RawSession.cpp
@@ -0,0 +1,146 @@
+//===- RawSession.cpp - Raw 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/RawSession.h"
+
+#include "llvm/DebugInfo/CodeView/ByteStream.h"
+#include "llvm/DebugInfo/CodeView/StreamInterface.h"
+#include "llvm/DebugInfo/PDB/GenericError.h"
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+namespace {
+// We need a class which behaves like an immutable ByteStream, but whose data
+// is backed by an llvm::MemoryBuffer. It also needs to own the underlying
+// MemoryBuffer, so this simple adapter is a good way to achieve that.
+class InputByteStream : public codeview::ByteStream<false> {
+public:
+ explicit InputByteStream(std::unique_ptr<MemoryBuffer> Buffer)
+ : ByteStream(ArrayRef<uint8_t>(Buffer->getBuffer().bytes_begin(),
+ Buffer->getBuffer().bytes_end())),
+ MemBuffer(std::move(Buffer)) {}
+
+ std::unique_ptr<MemoryBuffer> MemBuffer;
+};
+}
+
+RawSession::RawSession(std::unique_ptr<PDBFile> PdbFile)
+ : Pdb(std::move(PdbFile)) {}
+
+RawSession::~RawSession() {}
+
+Error RawSession::createFromPdb(StringRef Path,
+ std::unique_ptr<IPDBSession> &Session) {
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
+ MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1,
+ /*RequiresNullTerminator=*/false);
+ if (!ErrorOrBuffer)
+ return llvm::make_error<GenericError>(generic_error_code::invalid_path);
+
+ std::unique_ptr<MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
+ auto Stream = llvm::make_unique<InputByteStream>(std::move(Buffer));
+
+ std::unique_ptr<PDBFile> File(new PDBFile(std::move(Stream)));
+ if (auto EC = File->parseFileHeaders())
+ return EC;
+ if (auto EC = File->parseStreamData())
+ return EC;
+
+ Session.reset(new RawSession(std::move(File)));
+
+ return Error::success();
+}
+
+Error RawSession::createFromExe(StringRef Path,
+ std::unique_ptr<IPDBSession> &Session) {
+ return llvm::make_error<RawError>(raw_error_code::feature_unsupported);
+}
+
+uint64_t RawSession::getLoadAddress() const { return 0; }
+
+void RawSession::setLoadAddress(uint64_t Address) {}
+
+std::unique_ptr<PDBSymbolExe> RawSession::getGlobalScope() const {
+ return nullptr;
+}
+
+std::unique_ptr<PDBSymbol> RawSession::getSymbolById(uint32_t SymbolId) const {
+ return nullptr;
+}
+
+std::unique_ptr<PDBSymbol>
+RawSession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+RawSession::findLineNumbers(const PDBSymbolCompiland &Compiland,
+ const IPDBSourceFile &File) const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+RawSession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBEnumSourceFiles>
+RawSession::findSourceFiles(const PDBSymbolCompiland *Compiland,
+ llvm::StringRef Pattern,
+ PDB_NameSearchFlags Flags) const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBSourceFile>
+RawSession::findOneSourceFile(const PDBSymbolCompiland *Compiland,
+ llvm::StringRef Pattern,
+ PDB_NameSearchFlags Flags) const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
+RawSession::findCompilandsForSourceFile(llvm::StringRef Pattern,
+ PDB_NameSearchFlags Flags) const {
+ return nullptr;
+}
+
+std::unique_ptr<PDBSymbolCompiland>
+RawSession::findOneCompilandForSourceFile(llvm::StringRef Pattern,
+ PDB_NameSearchFlags Flags) const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBEnumSourceFiles> RawSession::getAllSourceFiles() const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBEnumSourceFiles> RawSession::getSourceFilesForCompiland(
+ const PDBSymbolCompiland &Compiland) const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBSourceFile>
+RawSession::getSourceFileById(uint32_t FileId) const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBEnumDataStreams> RawSession::getDebugStreams() const {
+ return nullptr;
+}
diff --git a/lib/DebugInfo/PDB/Raw/SymbolStream.cpp b/lib/DebugInfo/PDB/Raw/SymbolStream.cpp
new file mode 100644
index 000000000000..41b2a64bfb14
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/SymbolStream.cpp
@@ -0,0 +1,46 @@
+//===- SymbolStream.cpp - PDB Symbol Stream Access ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/SymbolStream.h"
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
+#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support;
+using namespace llvm::pdb;
+
+SymbolStream::SymbolStream(std::unique_ptr<MappedBlockStream> Stream)
+ : Stream(std::move(Stream)) {}
+
+SymbolStream::~SymbolStream() {}
+
+Error SymbolStream::reload() {
+ codeview::StreamReader Reader(*Stream);
+
+ if (auto EC = Reader.readArray(SymbolRecords, Stream->getLength()))
+ return EC;
+
+ return Error::success();
+}
+
+iterator_range<codeview::CVSymbolArray::Iterator>
+SymbolStream::getSymbols(bool *HadError) const {
+ return llvm::make_range(SymbolRecords.begin(HadError), SymbolRecords.end());
+}
+
+Error SymbolStream::commit() { return Error::success(); }
diff --git a/lib/DebugInfo/PDB/Raw/TpiStream.cpp b/lib/DebugInfo/PDB/Raw/TpiStream.cpp
new file mode 100644
index 000000000000..5617e57ccf67
--- /dev/null
+++ b/lib/DebugInfo/PDB/Raw/TpiStream.cpp
@@ -0,0 +1,273 @@
+//===- TpiStream.cpp - PDB Type Info (TPI) Stream 2 Access ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/PDB/Raw/Hash.h"
+#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
+#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
+
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::support;
+using namespace llvm::pdb;
+
+namespace {
+const uint32_t MinHashBuckets = 0x1000;
+const uint32_t MaxHashBuckets = 0x40000;
+}
+
+// This corresponds to `HDR` in PDB/dbi/tpi.h.
+struct TpiStream::HeaderInfo {
+ struct EmbeddedBuf {
+ little32_t Off;
+ ulittle32_t Length;
+ };
+
+ ulittle32_t Version;
+ ulittle32_t HeaderSize;
+ ulittle32_t TypeIndexBegin;
+ ulittle32_t TypeIndexEnd;
+ ulittle32_t TypeRecordBytes;
+
+ // The following members correspond to `TpiHash` in PDB/dbi/tpi.h.
+ ulittle16_t HashStreamIndex;
+ ulittle16_t HashAuxStreamIndex;
+ ulittle32_t HashKeySize;
+ ulittle32_t NumHashBuckets;
+
+ EmbeddedBuf HashValueBuffer;
+ EmbeddedBuf IndexOffsetBuffer;
+ EmbeddedBuf HashAdjBuffer;
+};
+
+TpiStream::TpiStream(const PDBFile &File,
+ std::unique_ptr<MappedBlockStream> Stream)
+ : Pdb(File), Stream(std::move(Stream)) {}
+
+TpiStream::~TpiStream() {}
+
+// Corresponds to `fUDTAnon`.
+template <typename T> static bool isAnonymous(T &Rec) {
+ StringRef Name = Rec.getName();
+ return Name == "<unnamed-tag>" || Name == "__unnamed" ||
+ Name.endswith("::<unnamed-tag>") || Name.endswith("::__unnamed");
+}
+
+// Computes a hash for a given TPI record.
+template <typename T>
+static uint32_t getTpiHash(T &Rec, const CVRecord<TypeLeafKind> &RawRec) {
+ auto Opts = static_cast<uint16_t>(Rec.getOptions());
+
+ bool ForwardRef =
+ Opts & static_cast<uint16_t>(ClassOptions::ForwardReference);
+ bool Scoped = Opts & static_cast<uint16_t>(ClassOptions::Scoped);
+ bool UniqueName = Opts & static_cast<uint16_t>(ClassOptions::HasUniqueName);
+ bool IsAnon = UniqueName && isAnonymous(Rec);
+
+ if (!ForwardRef && !Scoped && !IsAnon)
+ return hashStringV1(Rec.getName());
+ if (!ForwardRef && UniqueName && !IsAnon)
+ return hashStringV1(Rec.getUniqueName());
+ return hashBufferV8(RawRec.RawData);
+}
+
+namespace {
+class TpiHashVerifier : public TypeVisitorCallbacks {
+public:
+ TpiHashVerifier(FixedStreamArray<support::ulittle32_t> &HashValues,
+ uint32_t NumHashBuckets)
+ : HashValues(HashValues), NumHashBuckets(NumHashBuckets) {}
+
+ Error visitUdtSourceLine(UdtSourceLineRecord &Rec) override {
+ return verifySourceLine(Rec);
+ }
+
+ Error visitUdtModSourceLine(UdtModSourceLineRecord &Rec) override {
+ return verifySourceLine(Rec);
+ }
+
+ Error visitClass(ClassRecord &Rec) override { return verify(Rec); }
+ Error visitEnum(EnumRecord &Rec) override { return verify(Rec); }
+ Error visitUnion(UnionRecord &Rec) override { return verify(Rec); }
+
+ Error visitTypeBegin(const CVRecord<TypeLeafKind> &Rec) override {
+ ++Index;
+ RawRecord = &Rec;
+ return Error::success();
+ }
+
+private:
+ template <typename T> Error verify(T &Rec) {
+ uint32_t Hash = getTpiHash(Rec, *RawRecord);
+ if (Hash % NumHashBuckets != HashValues[Index])
+ return errorInvalidHash();
+ return Error::success();
+ }
+
+ template <typename T> Error verifySourceLine(T &Rec) {
+ char Buf[4];
+ support::endian::write32le(Buf, Rec.getUDT().getIndex());
+ uint32_t Hash = hashStringV1(StringRef(Buf, 4));
+ if (Hash % NumHashBuckets != HashValues[Index])
+ return errorInvalidHash();
+ return Error::success();
+ }
+
+ Error errorInvalidHash() {
+ return make_error<RawError>(
+ raw_error_code::invalid_tpi_hash,
+ "Type index is 0x" + utohexstr(TypeIndex::FirstNonSimpleIndex + Index));
+ }
+
+ FixedStreamArray<support::ulittle32_t> HashValues;
+ const CVRecord<TypeLeafKind> *RawRecord;
+ uint32_t NumHashBuckets;
+ uint32_t Index = -1;
+};
+}
+
+// Verifies that a given type record matches with a given hash value.
+// Currently we only verify SRC_LINE records.
+Error TpiStream::verifyHashValues() {
+ TpiHashVerifier Verifier(HashValues, Header->NumHashBuckets);
+ CVTypeVisitor Visitor(Verifier);
+ return Visitor.visitTypeStream(TypeRecords);
+}
+
+Error TpiStream::reload() {
+ StreamReader Reader(*Stream);
+
+ if (Reader.bytesRemaining() < sizeof(HeaderInfo))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "TPI Stream does not contain a header.");
+
+ if (Reader.readObject(Header))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "TPI Stream does not contain a header.");
+
+ if (Header->Version != PdbTpiV80)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Unsupported TPI Version.");
+
+ if (Header->HeaderSize != sizeof(HeaderInfo))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Corrupt TPI Header size.");
+
+ if (Header->HashKeySize != sizeof(ulittle32_t))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "TPI Stream expected 4 byte hash key size.");
+
+ if (Header->NumHashBuckets < MinHashBuckets ||
+ Header->NumHashBuckets > MaxHashBuckets)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "TPI Stream Invalid number of hash buckets.");
+
+ // The actual type records themselves come from this stream
+ if (auto EC = Reader.readArray(TypeRecords, Header->TypeRecordBytes))
+ return EC;
+
+ // Hash indices, hash values, etc come from the hash stream.
+ if (Header->HashStreamIndex >= Pdb.getNumStreams())
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid TPI hash stream index.");
+
+ auto HS =
+ MappedBlockStream::createIndexedStream(Header->HashStreamIndex, Pdb);
+ if (!HS)
+ return HS.takeError();
+ StreamReader HSR(**HS);
+
+ uint32_t NumHashValues = Header->HashValueBuffer.Length / sizeof(ulittle32_t);
+ if (NumHashValues != NumTypeRecords())
+ return make_error<RawError>(
+ raw_error_code::corrupt_file,
+ "TPI hash count does not match with the number of type records.");
+ HSR.setOffset(Header->HashValueBuffer.Off);
+ if (auto EC = HSR.readArray(HashValues, NumHashValues))
+ return EC;
+
+ HSR.setOffset(Header->IndexOffsetBuffer.Off);
+ uint32_t NumTypeIndexOffsets =
+ Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset);
+ if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets))
+ return EC;
+
+ HSR.setOffset(Header->HashAdjBuffer.Off);
+ uint32_t NumHashAdjustments =
+ Header->HashAdjBuffer.Length / sizeof(TypeIndexOffset);
+ if (auto EC = HSR.readArray(HashAdjustments, NumHashAdjustments))
+ return EC;
+
+ HashStream = std::move(*HS);
+
+ // TPI hash table is a parallel array for the type records.
+ // Verify that the hash values match with type records.
+ if (auto EC = verifyHashValues())
+ return EC;
+
+ return Error::success();
+}
+
+PdbRaw_TpiVer TpiStream::getTpiVersion() const {
+ uint32_t Value = Header->Version;
+ return static_cast<PdbRaw_TpiVer>(Value);
+}
+
+uint32_t TpiStream::TypeIndexBegin() const { return Header->TypeIndexBegin; }
+
+uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; }
+
+uint32_t TpiStream::NumTypeRecords() const {
+ return TypeIndexEnd() - TypeIndexBegin();
+}
+
+uint16_t TpiStream::getTypeHashStreamIndex() const {
+ return Header->HashStreamIndex;
+}
+
+uint16_t TpiStream::getTypeHashStreamAuxIndex() const {
+ return Header->HashAuxStreamIndex;
+}
+
+uint32_t TpiStream::NumHashBuckets() const { return Header->NumHashBuckets; }
+uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; }
+
+FixedStreamArray<support::ulittle32_t>
+TpiStream::getHashValues() const {
+ return HashValues;
+}
+
+FixedStreamArray<TypeIndexOffset>
+TpiStream::getTypeIndexOffsets() const {
+ return TypeIndexOffsets;
+}
+
+FixedStreamArray<TypeIndexOffset>
+TpiStream::getHashAdjustments() const {
+ return HashAdjustments;
+}
+
+iterator_range<CVTypeArray::Iterator>
+TpiStream::types(bool *HadError) const {
+ return llvm::make_range(TypeRecords.begin(HadError), TypeRecords.end());
+}
+
+Error TpiStream::commit() { return Error::success(); }
diff --git a/lib/DebugInfo/Symbolize/DIPrinter.cpp b/lib/DebugInfo/Symbolize/DIPrinter.cpp
index a9dee7abeed1..be5c603a38ef 100644
--- a/lib/DebugInfo/Symbolize/DIPrinter.cpp
+++ b/lib/DebugInfo/Symbolize/DIPrinter.cpp
@@ -13,9 +13,19 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/Symbolize/DIPrinter.h"
-
+#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <string>
namespace llvm {
namespace symbolize {
@@ -26,7 +36,7 @@ static const char kDILineInfoBadString[] = "<invalid>";
static const char kBadString[] = "??";
// Prints source code around in the FileName the Line.
-void DIPrinter::printContext(std::string FileName, int64_t Line) {
+void DIPrinter::printContext(const std::string &FileName, int64_t Line) {
if (PrintSourceContext <= 0)
return;
@@ -61,7 +71,7 @@ void DIPrinter::print(const DILineInfo &Info, bool Inlined) {
if (FunctionName == kDILineInfoBadString)
FunctionName = kBadString;
- StringRef Delimiter = (PrintPretty == true) ? " at " : "\n";
+ StringRef Delimiter = PrintPretty ? " at " : "\n";
StringRef Prefix = (PrintPretty && Inlined) ? " (inlined by) " : "";
OS << Prefix << FunctionName << Delimiter;
}
@@ -97,5 +107,5 @@ DIPrinter &DIPrinter::operator<<(const DIGlobal &Global) {
return *this;
}
-}
-}
+} // end namespace symbolize
+} // end namespace llvm
diff --git a/lib/DebugInfo/Symbolize/Makefile b/lib/DebugInfo/Symbolize/Makefile
deleted file mode 100644
index 17aac9396585..000000000000
--- a/lib/DebugInfo/Symbolize/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-##===- lib/DebugInfo/Symbolize/Makefile --------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../../..
-LIBRARYNAME = LLVMSymbolize
-BUILD_ARCHIVE := 1
-
-include $(LEVEL)/Makefile.common
-
diff --git a/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp b/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
index e31462459844..f6940080089f 100644
--- a/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
+++ b/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "SymbolizableObjectFile.h"
+#include "llvm/Object/COFF.h"
#include "llvm/Object/SymbolSize.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
@@ -119,12 +120,15 @@ std::error_code SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol,
uint64_t SymbolSize,
DataExtractor *OpdExtractor,
uint64_t OpdAddress) {
- SymbolRef::Type SymbolType = Symbol.getType();
+ Expected<SymbolRef::Type> SymbolTypeOrErr = Symbol.getType();
+ if (!SymbolTypeOrErr)
+ return errorToErrorCode(SymbolTypeOrErr.takeError());
+ SymbolRef::Type SymbolType = *SymbolTypeOrErr;
if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data)
return std::error_code();
- ErrorOr<uint64_t> SymbolAddressOrErr = Symbol.getAddress();
- if (auto EC = SymbolAddressOrErr.getError())
- return EC;
+ Expected<uint64_t> SymbolAddressOrErr = Symbol.getAddress();
+ if (!SymbolAddressOrErr)
+ return errorToErrorCode(SymbolAddressOrErr.takeError());
uint64_t SymbolAddress = *SymbolAddressOrErr;
if (OpdExtractor) {
// For big-endian PowerPC64 ELF, symbols in the .opd section refer to
@@ -138,9 +142,9 @@ std::error_code SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol,
OpdExtractor->isValidOffsetForAddress(OpdOffset32))
SymbolAddress = OpdExtractor->getAddress(&OpdOffset32);
}
- ErrorOr<StringRef> SymbolNameOrErr = Symbol.getName();
- if (auto EC = SymbolNameOrErr.getError())
- return EC;
+ Expected<StringRef> SymbolNameOrErr = Symbol.getName();
+ if (!SymbolNameOrErr)
+ return errorToErrorCode(SymbolNameOrErr.takeError());
StringRef SymbolName = *SymbolNameOrErr;
// Mach-O symbol table names have leading underscore, skip it.
if (Module->isMachO() && SymbolName.size() > 0 && SymbolName[0] == '_')
diff --git a/lib/DebugInfo/Symbolize/Symbolize.cpp b/lib/DebugInfo/Symbolize/Symbolize.cpp
index 3da1963bb791..adbe0cb69edb 100644
--- a/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -20,6 +20,7 @@
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/PDB/PDB.h"
#include "llvm/DebugInfo/PDB/PDBContext.h"
+#include "llvm/Object/COFF.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/MachOUniversal.h"
@@ -31,7 +32,10 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
-#include <stdlib.h>
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
#if defined(_MSC_VER)
#include <Windows.h>
@@ -47,12 +51,18 @@
namespace llvm {
namespace symbolize {
-ErrorOr<DILineInfo> LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
+Expected<DILineInfo> LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
uint64_t ModuleOffset) {
- auto InfoOrErr = getOrCreateModuleInfo(ModuleName);
- if (auto EC = InfoOrErr.getError())
- return EC;
- SymbolizableModule *Info = InfoOrErr.get();
+ SymbolizableModule *Info;
+ if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
+ Info = InfoOrErr.get();
+ else
+ return InfoOrErr.takeError();
+
+ // A null module means an error has already been reported. Return an empty
+ // result.
+ if (!Info)
+ return DILineInfo();
// If the user is giving us relative addresses, add the preferred base of the
// object to the offset before we do the query. It's what DIContext expects.
@@ -66,13 +76,19 @@ ErrorOr<DILineInfo> LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
return LineInfo;
}
-ErrorOr<DIInliningInfo>
+Expected<DIInliningInfo>
LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
uint64_t ModuleOffset) {
- auto InfoOrErr = getOrCreateModuleInfo(ModuleName);
- if (auto EC = InfoOrErr.getError())
- return EC;
- SymbolizableModule *Info = InfoOrErr.get();
+ SymbolizableModule *Info;
+ if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
+ Info = InfoOrErr.get();
+ else
+ return InfoOrErr.takeError();
+
+ // A null module means an error has already been reported. Return an empty
+ // result.
+ if (!Info)
+ return DIInliningInfo();
// If the user is giving us relative addresses, add the preferred base of the
// object to the offset before we do the query. It's what DIContext expects.
@@ -90,12 +106,18 @@ LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
return InlinedContext;
}
-ErrorOr<DIGlobal> LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
- uint64_t ModuleOffset) {
- auto InfoOrErr = getOrCreateModuleInfo(ModuleName);
- if (auto EC = InfoOrErr.getError())
- return EC;
- SymbolizableModule *Info = InfoOrErr.get();
+Expected<DIGlobal> LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
+ uint64_t ModuleOffset) {
+ SymbolizableModule *Info;
+ if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
+ Info = InfoOrErr.get();
+ else
+ return InfoOrErr.takeError();
+
+ // A null module means an error has already been reported. Return an empty
+ // result.
+ if (!Info)
+ return DIGlobal();
// If the user is giving us relative addresses, add the preferred base of
// the object to the offset before we do the query. It's what DIContext
@@ -116,11 +138,12 @@ void LLVMSymbolizer::flush() {
Modules.clear();
}
+namespace {
+
// For Path="/path/to/foo" and Basename="foo" assume that debug info is in
// /path/to/foo.dSYM/Contents/Resources/DWARF/foo.
// For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in
// /path/to/bar.dSYM/Contents/Resources/DWARF/foo.
-static
std::string getDarwinDWARFResourceForPath(
const std::string &Path, const std::string &Basename) {
SmallString<16> ResourceName = StringRef(Path);
@@ -132,7 +155,7 @@ std::string getDarwinDWARFResourceForPath(
return ResourceName.str();
}
-static bool checkFileCRC(StringRef Path, uint32_t CRCHash) {
+bool checkFileCRC(StringRef Path, uint32_t CRCHash) {
ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
MemoryBuffer::getFileOrSTDIN(Path);
if (!MB)
@@ -140,9 +163,9 @@ static bool checkFileCRC(StringRef Path, uint32_t CRCHash) {
return !zlib::isAvailable() || CRCHash == zlib::crc32(MB.get()->getBuffer());
}
-static bool findDebugBinary(const std::string &OrigPath,
- const std::string &DebuglinkName, uint32_t CRCHash,
- std::string &Result) {
+bool findDebugBinary(const std::string &OrigPath,
+ const std::string &DebuglinkName, uint32_t CRCHash,
+ std::string &Result) {
std::string OrigRealPath = OrigPath;
#if defined(HAVE_REALPATH)
if (char *RP = realpath(OrigPath.c_str(), nullptr)) {
@@ -177,8 +200,8 @@ static bool findDebugBinary(const std::string &OrigPath,
return false;
}
-static bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName,
- uint32_t &CRCHash) {
+bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName,
+ uint32_t &CRCHash) {
if (!Obj)
return false;
for (const SectionRef &Section : Obj->sections()) {
@@ -205,7 +228,6 @@ static bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugNam
return false;
}
-static
bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj,
const MachOObjectFile *Obj) {
ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid();
@@ -215,6 +237,8 @@ bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj,
return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size());
}
+} // end anonymous namespace
+
ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
const MachOObjectFile *MachExeObj, const std::string &ArchName) {
// On Darwin we may find DWARF in separate object file in
@@ -227,9 +251,14 @@ ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
}
for (const auto &Path : DsymPaths) {
auto DbgObjOrErr = getOrCreateObject(Path, ArchName);
- if (!DbgObjOrErr)
+ if (!DbgObjOrErr) {
+ // Ignore errors, the file might not exist.
+ consumeError(DbgObjOrErr.takeError());
continue;
+ }
ObjectFile *DbgObj = DbgObjOrErr.get();
+ if (!DbgObj)
+ continue;
const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj);
if (!MachDbgObj)
continue;
@@ -250,23 +279,27 @@ ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path,
if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath))
return nullptr;
auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
- if (!DbgObjOrErr)
+ if (!DbgObjOrErr) {
+ // Ignore errors, the file might not exist.
+ consumeError(DbgObjOrErr.takeError());
return nullptr;
+ }
return DbgObjOrErr.get();
}
-ErrorOr<LLVMSymbolizer::ObjectPair>
+Expected<LLVMSymbolizer::ObjectPair>
LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
const std::string &ArchName) {
const auto &I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
- if (I != ObjectPairForPathArch.end())
+ if (I != ObjectPairForPathArch.end()) {
return I->second;
+ }
auto ObjOrErr = getOrCreateObject(Path, ArchName);
- if (auto EC = ObjOrErr.getError()) {
- ObjectPairForPathArch.insert(
- std::make_pair(std::make_pair(Path, ArchName), EC));
- return EC;
+ if (!ObjOrErr) {
+ ObjectPairForPathArch.insert(std::make_pair(std::make_pair(Path, ArchName),
+ ObjectPair(nullptr, nullptr)));
+ return ObjOrErr.takeError();
}
ObjectFile *Obj = ObjOrErr.get();
@@ -285,40 +318,37 @@ LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
return Res;
}
-ErrorOr<ObjectFile *>
+Expected<ObjectFile *>
LLVMSymbolizer::getOrCreateObject(const std::string &Path,
const std::string &ArchName) {
const auto &I = BinaryForPath.find(Path);
Binary *Bin = nullptr;
if (I == BinaryForPath.end()) {
- ErrorOr<OwningBinary<Binary>> BinOrErr = createBinary(Path);
- if (auto EC = BinOrErr.getError()) {
- BinaryForPath.insert(std::make_pair(Path, EC));
- return EC;
+ Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path);
+ if (!BinOrErr) {
+ BinaryForPath.insert(std::make_pair(Path, OwningBinary<Binary>()));
+ return BinOrErr.takeError();
}
Bin = BinOrErr->getBinary();
BinaryForPath.insert(std::make_pair(Path, std::move(BinOrErr.get())));
- } else if (auto EC = I->second.getError()) {
- return EC;
} else {
- Bin = I->second->getBinary();
+ Bin = I->second.getBinary();
}
- assert(Bin != nullptr);
+ if (!Bin)
+ return static_cast<ObjectFile *>(nullptr);
- if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) {
+ if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) {
const auto &I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
if (I != ObjectForUBPathAndArch.end()) {
- if (auto EC = I->second.getError())
- return EC;
- return I->second->get();
+ return I->second.get();
}
- ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr =
+ Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
UB->getObjectForArch(ArchName);
- if (auto EC = ObjOrErr.getError()) {
- ObjectForUBPathAndArch.insert(
- std::make_pair(std::make_pair(Path, ArchName), EC));
- return EC;
+ if (!ObjOrErr) {
+ ObjectForUBPathAndArch.insert(std::make_pair(
+ std::make_pair(Path, ArchName), std::unique_ptr<ObjectFile>()));
+ return ObjOrErr.takeError();
}
ObjectFile *Res = ObjOrErr->get();
ObjectForUBPathAndArch.insert(std::make_pair(std::make_pair(Path, ArchName),
@@ -328,17 +358,14 @@ LLVMSymbolizer::getOrCreateObject(const std::string &Path,
if (Bin->isObject()) {
return cast<ObjectFile>(Bin);
}
- return object_error::arch_not_found;
+ return errorCodeToError(object_error::arch_not_found);
}
-ErrorOr<SymbolizableModule *>
+Expected<SymbolizableModule *>
LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
const auto &I = Modules.find(ModuleName);
if (I != Modules.end()) {
- auto &InfoOrErr = I->second;
- if (auto EC = InfoOrErr.getError())
- return EC;
- return InfoOrErr->get();
+ return I->second.get();
}
std::string BinaryName = ModuleName;
std::string ArchName = Opts.DefaultArch;
@@ -352,21 +379,30 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
}
}
auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName);
- if (auto EC = ObjectsOrErr.getError()) {
+ if (!ObjectsOrErr) {
// Failed to find valid object file.
- Modules.insert(std::make_pair(ModuleName, EC));
- return EC;
+ Modules.insert(
+ std::make_pair(ModuleName, std::unique_ptr<SymbolizableModule>()));
+ return ObjectsOrErr.takeError();
}
ObjectPair Objects = ObjectsOrErr.get();
std::unique_ptr<DIContext> Context;
+ // If this is a COFF object containing PDB info, use a PDBContext to
+ // symbolize. Otherwise, use DWARF.
if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
- // If this is a COFF object, assume it contains PDB debug information. If
- // we don't find any we will fall back to the DWARF case.
- std::unique_ptr<IPDBSession> Session;
- PDB_ErrorCode Error = loadDataForEXE(PDB_ReaderType::DIA,
- Objects.first->getFileName(), Session);
- if (Error == PDB_ErrorCode::Success) {
+ const debug_pdb_info *PDBInfo;
+ StringRef PDBFileName;
+ auto EC = CoffObject->getDebugPDBInfo(PDBInfo, PDBFileName);
+ if (!EC && PDBInfo != nullptr) {
+ using namespace pdb;
+ std::unique_ptr<IPDBSession> Session;
+ if (auto Err = loadDataForEXE(PDB_ReaderType::DIA,
+ Objects.first->getFileName(), Session)) {
+ Modules.insert(
+ std::make_pair(ModuleName, std::unique_ptr<SymbolizableModule>()));
+ return std::move(Err);
+ }
Context.reset(new PDBContext(*CoffObject, std::move(Session)));
}
}
@@ -375,21 +411,26 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
assert(Context);
auto InfoOrErr =
SymbolizableObjectFile::create(Objects.first, std::move(Context));
+ std::unique_ptr<SymbolizableModule> SymMod;
+ if (InfoOrErr)
+ SymMod = std::move(InfoOrErr.get());
auto InsertResult =
- Modules.insert(std::make_pair(ModuleName, std::move(InfoOrErr)));
+ Modules.insert(std::make_pair(ModuleName, std::move(SymMod)));
assert(InsertResult.second);
- if (auto EC = InsertResult.first->second.getError())
- return EC;
- return InsertResult.first->second->get();
+ if (auto EC = InfoOrErr.getError())
+ return errorCodeToError(EC);
+ return InsertResult.first->second.get();
}
+namespace {
+
// Undo these various manglings for Win32 extern "C" functions:
// cdecl - _foo
// stdcall - _foo@12
// fastcall - @foo@12
// vectorcall - foo@@12
// These are all different linkage names for 'foo'.
-static StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
+StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
// Remove any '_' or '@' prefix.
char Front = SymbolName.empty() ? '\0' : SymbolName[0];
if (Front == '_' || Front == '@')
@@ -412,6 +453,8 @@ static StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
return SymbolName;
}
+} // end anonymous namespace
+
#if !defined(_MSC_VER)
// Assume that __cxa_demangle is provided by libcxxabi (except for Windows).
extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer,