summaryrefslogtreecommitdiffstats
path: root/llvm/lib/DebugInfo
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2017-02-16 23:35:45 +0000
committerZachary Turner <zturner@google.com>2017-02-16 23:35:45 +0000
commit7b327d051b12f90e4650a8ac48cd3f7b3ee1c4e9 (patch)
tree8bf152120db1248d4f0a38028cda19909986f907 /llvm/lib/DebugInfo
parent55aaa844cb12923529c9ff128be22cdaddcce9dd (diff)
downloadbcm5719-llvm-7b327d051b12f90e4650a8ac48cd3f7b3ee1c4e9.tar.gz
bcm5719-llvm-7b327d051b12f90e4650a8ac48cd3f7b3ee1c4e9.zip
[pdb] Add the ability to resolve TypeServer PDBs.
Some PDBs or object files can contain references to other PDBs where the real type information lives. When this happens, all type indices in the original PDB are meaningless because their records are not there. With this patch we add the ability to pull type info from those secondary PDBs. Differential Revision: https://reviews.llvm.org/D29973 llvm-svn: 295382
Diffstat (limited to 'llvm/lib/DebugInfo')
-rw-r--r--llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp4
-rw-r--r--llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp69
-rw-r--r--llvm/lib/DebugInfo/CodeView/CodeViewError.cpp2
-rw-r--r--llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp11
-rw-r--r--llvm/lib/DebugInfo/PDB/CMakeLists.txt1
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp2
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp11
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp119
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp3
9 files changed, 213 insertions, 9 deletions
diff --git a/llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp b/llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp
index fcd239cce0d..c7cd58a10e6 100644
--- a/llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp
+++ b/llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp
@@ -28,6 +28,8 @@ Error CVTypeDumper::dump(const CVType &Record, TypeVisitorCallbacks &Dumper) {
Pipeline.addCallbackToPipeline(Dumper);
CVTypeVisitor Visitor(Pipeline);
+ if (Handler)
+ Visitor.addTypeServerHandler(*Handler);
CVType RecordCopy = Record;
if (auto EC = Visitor.visitTypeRecord(RecordCopy))
@@ -45,6 +47,8 @@ Error CVTypeDumper::dump(const CVTypeArray &Types,
Pipeline.addCallbackToPipeline(Dumper);
CVTypeVisitor Visitor(Pipeline);
+ if (Handler)
+ Visitor.addTypeServerHandler(*Handler);
if (auto EC = Visitor.visitTypeStream(Types))
return EC;
diff --git a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
index 5171e24f3aa..48160252c6d 100644
--- a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
+++ b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
@@ -10,9 +10,14 @@
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
+#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/MSF/ByteStream.h"
+#include "llvm/DebugInfo/MSF/StreamReader.h"
using namespace llvm;
using namespace llvm::codeview;
@@ -21,7 +26,8 @@ CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
: Callbacks(Callbacks) {}
template <typename T>
-static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
+static Error visitKnownRecord(CVTypeVisitor &Visitor, CVType &Record,
+ TypeVisitorCallbacks &Callbacks) {
TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Type);
T KnownRecord(RK);
if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
@@ -39,7 +45,58 @@ static Error visitKnownMember(CVMemberRecord &Record,
return Error::success();
}
+static Expected<TypeServer2Record> deserializeTypeServerRecord(CVType &Record) {
+ class StealTypeServerVisitor : public TypeVisitorCallbacks {
+ public:
+ explicit StealTypeServerVisitor(TypeServer2Record &TR) : TR(TR) {}
+
+ Error visitKnownRecord(CVType &CVR, TypeServer2Record &Record) override {
+ TR = Record;
+ return Error::success();
+ }
+
+ private:
+ TypeServer2Record &TR;
+ };
+
+ TypeServer2Record R(TypeRecordKind::TypeServer2);
+ TypeDeserializer Deserializer;
+ StealTypeServerVisitor Thief(R);
+ TypeVisitorCallbackPipeline Pipeline;
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Thief);
+ CVTypeVisitor Visitor(Pipeline);
+ if (auto EC = Visitor.visitTypeRecord(Record))
+ return std::move(EC);
+
+ return R;
+}
+
+void CVTypeVisitor::addTypeServerHandler(TypeServerHandler &Handler) {
+ Handlers.push_back(&Handler);
+}
+
Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
+ if (Record.Type == TypeLeafKind::LF_TYPESERVER2 && !Handlers.empty()) {
+ auto TS = deserializeTypeServerRecord(Record);
+ if (!TS)
+ return TS.takeError();
+
+ for (auto Handler : Handlers) {
+ auto ExpectedResult = Handler->handle(*TS, Callbacks);
+ // If there was an error, return the error.
+ if (!ExpectedResult)
+ return ExpectedResult.takeError();
+
+ // If the handler processed the record, return success.
+ if (*ExpectedResult)
+ return Error::success();
+
+ // Otherwise keep searching for a handler, eventually falling out and
+ // using the default record handler.
+ }
+ }
+
if (auto EC = Callbacks.visitTypeBegin(Record))
return EC;
@@ -50,7 +107,7 @@ Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
break;
#define TYPE_RECORD(EnumName, EnumVal, Name) \
case EnumName: { \
- if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
+ if (auto EC = visitKnownRecord<Name##Record>(*this, Record, Callbacks)) \
return EC; \
break; \
}
@@ -109,6 +166,14 @@ Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
return Error::success();
}
+Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
+ for (auto I : Types) {
+ if (auto EC = visitTypeRecord(I))
+ return EC;
+ }
+ return Error::success();
+}
+
Error CVTypeVisitor::visitFieldListMemberStream(msf::StreamReader Reader) {
FieldListDeserializer Deserializer(Reader);
TypeVisitorCallbackPipeline Pipeline;
diff --git a/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp b/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp
index 55c10c076ee..8de266b836b 100644
--- a/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp
+++ b/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp
@@ -31,6 +31,8 @@ public:
"bytes.";
case cv_error_code::corrupt_record:
return "The CodeView record is corrupted.";
+ case cv_error_code::no_records:
+ return "There are no records";
case cv_error_code::operation_unsupported:
return "The requested operation is not supported.";
case cv_error_code::unknown_member_record:
diff --git a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
index 07984ad2fe3..85104d25cb4 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
@@ -54,8 +54,9 @@ namespace {
/// existing destination type index.
class TypeStreamMerger : public TypeVisitorCallbacks {
public:
- TypeStreamMerger(TypeTableBuilder &DestStream)
- : DestStream(DestStream), FieldListBuilder(DestStream) {}
+ TypeStreamMerger(TypeTableBuilder &DestStream, TypeServerHandler *Handler)
+ : DestStream(DestStream), FieldListBuilder(DestStream), Handler(Handler) {
+ }
/// TypeVisitorCallbacks overrides.
#define TYPE_RECORD(EnumName, EnumVal, Name) \
@@ -109,6 +110,7 @@ private:
TypeTableBuilder &DestStream;
FieldListRecordBuilder FieldListBuilder;
+ TypeServerHandler *Handler;
bool IsInFieldList{false};
size_t BeginIndexMapSize = 0;
@@ -175,6 +177,8 @@ Error TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
Pipeline.addCallbackToPipeline(*this);
CVTypeVisitor Visitor(Pipeline);
+ if (Handler)
+ Visitor.addTypeServerHandler(*Handler);
if (auto EC = Visitor.visitTypeStream(Types))
return EC;
@@ -186,6 +190,7 @@ Error TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
}
Error llvm::codeview::mergeTypeStreams(TypeTableBuilder &DestStream,
+ TypeServerHandler *Handler,
const CVTypeArray &Types) {
- return TypeStreamMerger(DestStream).mergeStream(Types);
+ return TypeStreamMerger(DestStream, Handler).mergeStream(Types);
}
diff --git a/llvm/lib/DebugInfo/PDB/CMakeLists.txt b/llvm/lib/DebugInfo/PDB/CMakeLists.txt
index 774edcd4011..4d4eb6ceaf1 100644
--- a/llvm/lib/DebugInfo/PDB/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/PDB/CMakeLists.txt
@@ -44,6 +44,7 @@ add_pdb_impl_folder(Native
Native/NativeSession.cpp
Native/PDBFile.cpp
Native/PDBFileBuilder.cpp
+ Native/PDBTypeServerHandler.cpp
Native/PublicsStream.cpp
Native/RawError.cpp
Native/StringTable.cpp
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
index e2c23317511..cafaa9bffa3 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
@@ -47,7 +47,7 @@ Error NativeSession::createFromPdb(StringRef Path,
auto Stream = llvm::make_unique<MemoryBufferByteStream>(std::move(Buffer));
auto Allocator = llvm::make_unique<BumpPtrAllocator>();
- auto File = llvm::make_unique<PDBFile>(std::move(Stream), *Allocator);
+ auto File = llvm::make_unique<PDBFile>(Path, std::move(Stream), *Allocator);
if (auto EC = File->parseFileHeaders())
return EC;
if (auto EC = File->parseStreamData())
diff --git a/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp
index 02e883b8418..3a3692dcac5 100644
--- a/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp
@@ -25,6 +25,7 @@
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/Path.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
@@ -38,12 +39,18 @@ namespace {
typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
} // end anonymous namespace
-PDBFile::PDBFile(std::unique_ptr<ReadableStream> PdbFileBuffer,
+PDBFile::PDBFile(StringRef Path, std::unique_ptr<ReadableStream> PdbFileBuffer,
BumpPtrAllocator &Allocator)
- : Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {}
+ : FilePath(Path), Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {}
PDBFile::~PDBFile() = default;
+StringRef PDBFile::getFilePath() const { return FilePath; }
+
+StringRef PDBFile::getFileDirectory() const {
+ return sys::path::parent_path(FilePath);
+}
+
uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; }
uint32_t PDBFile::getFreeBlockMapBlock() const {
diff --git a/llvm/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp
new file mode 100644
index 00000000000..629f3e80b0e
--- /dev/null
+++ b/llvm/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp
@@ -0,0 +1,119 @@
+//===- PDBTypeServerHandler.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Handles CodeView LF_TYPESERVER2 records by attempting to locate a matching
+// PDB file, then loading the PDB file and visiting all types from the
+// referenced PDB using the original supplied visitor.
+//
+// The net effect of this is that when visiting a PDB containing a TypeServer
+// record, the TypeServer record is "replaced" with all of the records in
+// the referenced PDB file. If a single instance of PDBTypeServerHandler
+// encounters the same TypeServer multiple times (for example reusing one
+// PDBTypeServerHandler across multiple visitations of distinct object files or
+// PDB files), PDBTypeServerHandler will optionally revisit all the records
+// again, or simply consume the record and do nothing.
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/PDB/GenericError.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static void ignoreErrors(Error EC) {
+ llvm::handleAllErrors(std::move(EC), [&](ErrorInfoBase &EIB) {});
+}
+
+PDBTypeServerHandler::PDBTypeServerHandler(bool RevisitAlways)
+ : RevisitAlways(RevisitAlways) {}
+
+void PDBTypeServerHandler::addSearchPath(StringRef Path) {
+ if (Path.empty() || !sys::fs::is_directory(Path))
+ return;
+
+ SearchPaths.push_back(Path);
+}
+
+Expected<bool>
+PDBTypeServerHandler::handleInternal(PDBFile &File,
+ TypeVisitorCallbacks &Callbacks) {
+ auto ExpectedTpi = File.getPDBTpiStream();
+ if (!ExpectedTpi)
+ return ExpectedTpi.takeError();
+ CVTypeVisitor Visitor(Callbacks);
+
+ if (auto EC = Visitor.visitTypeStream(ExpectedTpi->types(nullptr)))
+ return std::move(EC);
+
+ return true;
+}
+
+Expected<bool> PDBTypeServerHandler::handle(TypeServer2Record &TS,
+ TypeVisitorCallbacks &Callbacks) {
+ if (Session) {
+ // If we've already handled this TypeServer and we only want to handle each
+ // TypeServer once, consume the record without doing anything.
+ if (!RevisitAlways)
+ return true;
+
+ return handleInternal(Session->getPDBFile(), Callbacks);
+ }
+
+ StringRef File = sys::path::filename(TS.Name);
+ if (File.empty())
+ return make_error<CodeViewError>(
+ cv_error_code::corrupt_record,
+ "TypeServer2Record does not contain filename!");
+
+ for (auto Path : SearchPaths) {
+ sys::path::append(Path, File);
+ if (!sys::fs::exists(Path))
+ continue;
+
+ std::unique_ptr<IPDBSession> ThisSession;
+ if (auto EC = loadDataForPDB(PDB_ReaderType::Native, Path, ThisSession)) {
+ // It is not an error if this PDB fails to load, it just means that it
+ // doesn't match and we should continue searching.
+ ignoreErrors(std::move(EC));
+ continue;
+ }
+
+ std::unique_ptr<NativeSession> NS(
+ static_cast<NativeSession *>(ThisSession.release()));
+ PDBFile &File = NS->getPDBFile();
+ auto ExpectedInfo = File.getPDBInfoStream();
+ // All PDB Files should have an Info stream.
+ if (!ExpectedInfo)
+ return ExpectedInfo.takeError();
+
+ // Just because a file with a matching name was found and it was an actual
+ // PDB file doesn't mean it matches. For it to match the InfoStream's GUID
+ // must match the GUID specified in the TypeServer2 record.
+ ArrayRef<uint8_t> GuidBytes(ExpectedInfo->getGuid().Guid);
+ StringRef GuidStr(reinterpret_cast<const char *>(GuidBytes.begin()),
+ GuidBytes.size());
+ if (GuidStr != TS.Guid)
+ continue;
+
+ Session = std::move(NS);
+ return handleInternal(File, Callbacks);
+ }
+
+ // We couldn't find a matching PDB, so let it be handled by someone else.
+ return false;
+}
diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp
index 603a2c5e833..a24291f5cd4 100644
--- a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp
@@ -16,6 +16,7 @@
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/DebugInfo/MSF/StreamReader.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
@@ -164,7 +165,7 @@ FixedStreamArray<TypeIndexOffset> TpiStream::getTypeIndexOffsets() const {
HashTable &TpiStream::getHashAdjusters() { return HashAdjusters; }
-iterator_range<CVTypeArray::Iterator> TpiStream::types(bool *HadError) const {
+CVTypeRange TpiStream::types(bool *HadError) const {
return make_range(TypeRecords.begin(HadError), TypeRecords.end());
}
OpenPOWER on IntegriCloud