From: Zachary Turner Date: Tue, 8 Aug 2017 18:34:44 +0000 (+0000) Subject: [PDB] Fix linking of function symbols and local variables. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e87e5c313d6d32043232a95d1c963b613b083652;p=llvm [PDB] Fix linking of function symbols and local variables. The compiler outputs PROC32_ID symbols into the object files for functions, and these symbols have an embedded type index which, when copied to the PDB, refer to the IPI stream. However, the symbols themselves are also converted into regular symbols (e.g. S_GPROC32_ID -> S_GPROC32), and type indices in the regular symbol records refer to the TPI stream. So this patch applies two fixes to function records. 1. It converts ID symbols to the proper non-ID record type. 2. After remapping the type index from the object file's index space to the PDB file/IPI stream's index space, it then remaps that index to the TPI stream's index space by. Besides functions, during the remapping process we were also discarding symbol record types which we did not recognize. In particular, we were discarding S_BPREL32 records, which is what MSVC uses to describe local variables on the stack. So this patch fixes that as well by copying them to the PDB. Differential Revision: https://reviews.llvm.org/D36426 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@310394 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/DebugInfo/CodeView/TypeDeserializer.h b/include/llvm/DebugInfo/CodeView/TypeDeserializer.h index 965cdfd85f4..23d4f8a5e17 100644 --- a/include/llvm/DebugInfo/CodeView/TypeDeserializer.h +++ b/include/llvm/DebugInfo/CodeView/TypeDeserializer.h @@ -52,6 +52,21 @@ public: return Error::success(); } + template + static Expected deserializeAs(ArrayRef Data) { + CVType CVT; + CVT.RecordData = Data; + MappingInfo I(CVT.content()); + const RecordPrefix *Prefix = + reinterpret_cast(Data.data()); + TypeRecordKind K = + static_cast(uint16_t(Prefix->RecordKind)); + T Record(K); + if (auto EC = deserializeAs(CVT, Record)) + return std::move(EC); + return Record; + } + Error visitTypeBegin(CVType &Record) override { assert(!Mapping && "Already in a type mapping!"); Mapping = llvm::make_unique(Record.content()); diff --git a/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h b/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h index afe8942159e..c424a09ece8 100644 --- a/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h +++ b/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h @@ -30,11 +30,17 @@ void discoverTypeIndices(const CVType &Type, SmallVectorImpl &Refs); void discoverTypeIndices(const CVType &Type, SmallVectorImpl &Indices); +void discoverTypeIndices(ArrayRef RecordData, + SmallVectorImpl &Indices); /// Discover type indices in symbol records. Returns false if this is an unknown /// record. -bool discoverTypeIndices(const CVSymbol &Symbol, - SmallVectorImpl &Refs); +bool discoverTypeIndicesInSymbol(const CVSymbol &Symbol, + SmallVectorImpl &Refs); +bool discoverTypeIndicesInSymbol(ArrayRef RecordData, + SmallVectorImpl &Refs); +bool discoverTypeIndicesInSymbol(ArrayRef RecordData, + SmallVectorImpl &Indices); } } diff --git a/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp index 0d935c4472a..650f1942b94 100644 --- a/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp +++ b/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp @@ -395,6 +395,7 @@ static bool discoverTypeIndices(ArrayRef Content, SymbolKind Kind, case SymbolKind::S_CONSTANT: Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type break; + case SymbolKind::S_BPREL32: case SymbolKind::S_REGREL32: Refs.push_back({TiRefKind::TypeRef, 4, 1}); // Type break; @@ -450,17 +451,17 @@ void llvm::codeview::discoverTypeIndices(const CVType &Type, ::discoverTypeIndices(Type.content(), Type.kind(), Refs); } -void llvm::codeview::discoverTypeIndices(const CVType &Type, - SmallVectorImpl &Indices) { - +static void resolveTypeIndexReferences(ArrayRef RecordData, + ArrayRef Refs, + SmallVectorImpl &Indices) { Indices.clear(); - SmallVector Refs; - discoverTypeIndices(Type, Refs); if (Refs.empty()) return; - BinaryStreamReader Reader(Type.content(), support::little); + RecordData = RecordData.drop_front(sizeof(RecordPrefix)); + + BinaryStreamReader Reader(RecordData, support::little); for (const auto &Ref : Refs) { Reader.setOffset(Ref.Offset); FixedStreamArray Run; @@ -469,6 +470,18 @@ void llvm::codeview::discoverTypeIndices(const CVType &Type, } } +void llvm::codeview::discoverTypeIndices(const CVType &Type, + SmallVectorImpl &Indices) { + return discoverTypeIndices(Type.RecordData, Indices); +} + +void llvm::codeview::discoverTypeIndices(ArrayRef RecordData, + SmallVectorImpl &Indices) { + SmallVector Refs; + discoverTypeIndices(RecordData, Refs); + resolveTypeIndexReferences(RecordData, Refs, Indices); +} + void llvm::codeview::discoverTypeIndices(ArrayRef RecordData, SmallVectorImpl &Refs) { const RecordPrefix *P = @@ -477,8 +490,26 @@ void llvm::codeview::discoverTypeIndices(ArrayRef RecordData, ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs); } -bool llvm::codeview::discoverTypeIndices(const CVSymbol &Sym, - SmallVectorImpl &Refs) { +bool llvm::codeview::discoverTypeIndicesInSymbol( + const CVSymbol &Sym, SmallVectorImpl &Refs) { SymbolKind K = Sym.kind(); return ::discoverTypeIndices(Sym.content(), K, Refs); } + +bool llvm::codeview::discoverTypeIndicesInSymbol( + ArrayRef RecordData, SmallVectorImpl &Refs) { + const RecordPrefix *P = + reinterpret_cast(RecordData.data()); + SymbolKind K = static_cast(uint16_t(P->RecordKind)); + return ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, + Refs); +} + +bool llvm::codeview::discoverTypeIndicesInSymbol( + ArrayRef RecordData, SmallVectorImpl &Indices) { + SmallVector Refs; + if (!discoverTypeIndicesInSymbol(RecordData, Refs)) + return false; + resolveTypeIndexReferences(RecordData, Refs, Indices); + return true; +} diff --git a/tools/llvm-pdbutil/DumpOutputStyle.cpp b/tools/llvm-pdbutil/DumpOutputStyle.cpp index 99dd358fbf9..73e4a14a854 100644 --- a/tools/llvm-pdbutil/DumpOutputStyle.cpp +++ b/tools/llvm-pdbutil/DumpOutputStyle.cpp @@ -837,6 +837,7 @@ Error DumpOutputStyle::dumpModuleSyms() { ExitOnError Err("Unexpected error processing symbols: "); + auto &Ids = Err(initializeTypes(StreamIPI)); auto &Types = Err(initializeTypes(StreamTPI)); iterateModules( @@ -852,7 +853,8 @@ Error DumpOutputStyle::dumpModuleSyms() { SymbolVisitorCallbackPipeline Pipeline; SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); - MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types); + MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, + Types); Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Dumper); @@ -936,9 +938,13 @@ Error DumpOutputStyle::dumpSymbolsFromGSI(const GSIHashTable &Table, auto ExpectedTypes = initializeTypes(StreamTPI); if (!ExpectedTypes) return ExpectedTypes.takeError(); + auto ExpectedIds = initializeTypes(StreamIPI); + if (!ExpectedIds) + return ExpectedIds.takeError(); SymbolVisitorCallbackPipeline Pipeline; SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); - MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, *ExpectedTypes); + MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, *ExpectedIds, + *ExpectedTypes); Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Dumper); diff --git a/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/tools/llvm-pdbutil/MinimalSymbolDumper.cpp index fd186bc5a88..cc592b724df 100644 --- a/tools/llvm-pdbutil/MinimalSymbolDumper.cpp +++ b/tools/llvm-pdbutil/MinimalSymbolDumper.cpp @@ -389,10 +389,12 @@ Error MinimalSymbolDumper::visitSymbolEnd(CVSymbol &Record) { return Error::success(); } -std::string MinimalSymbolDumper::typeIndex(TypeIndex TI) const { +std::string MinimalSymbolDumper::typeOrIdIndex(codeview::TypeIndex TI, + bool IsType) const { if (TI.isSimple()) return formatv("{0}", TI).str(); - StringRef Name = Types.getTypeName(TI); + auto &Container = IsType ? Types : Ids; + StringRef Name = Container.getTypeName(TI); if (Name.size() > 32) { Name = Name.take_front(32); return formatv("{0} ({1}...)", TI, Name); @@ -400,6 +402,14 @@ std::string MinimalSymbolDumper::typeIndex(TypeIndex TI) const { return formatv("{0} ({1})", TI, Name); } +std::string MinimalSymbolDumper::idIndex(codeview::TypeIndex TI) const { + return typeOrIdIndex(TI, false); +} + +std::string MinimalSymbolDumper::typeIndex(TypeIndex TI) const { + return typeOrIdIndex(TI, true); +} + Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) { P.format(" `{0}`", Block.Name); AutoIndent Indent(P, 7); @@ -727,9 +737,19 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) { Proc.Parent, Proc.End, formatSegmentOffset(Proc.Segment, Proc.CodeOffset), Proc.CodeSize); - // FIXME: It seems FunctionType is sometimes an id and sometimes a type. + bool IsType = true; + switch (Proc.getKind()) { + case SymbolRecordKind::GlobalProcIdSym: + case SymbolRecordKind::ProcIdSym: + case SymbolRecordKind::DPCProcIdSym: + IsType = false; + break; + default: + break; + } P.formatLine("type = `{0}`, debug start = {1}, debug end = {2}, flags = {3}", - typeIndex(Proc.FunctionType), Proc.DbgStart, Proc.DbgEnd, + typeOrIdIndex(Proc.FunctionType, IsType), Proc.DbgStart, + Proc.DbgEnd, formatProcSymFlags(P.getIndentLevel() + 9, Proc.Flags)); return Error::success(); } diff --git a/tools/llvm-pdbutil/MinimalSymbolDumper.h b/tools/llvm-pdbutil/MinimalSymbolDumper.h index 5e30959ea9c..a140af74b69 100644 --- a/tools/llvm-pdbutil/MinimalSymbolDumper.h +++ b/tools/llvm-pdbutil/MinimalSymbolDumper.h @@ -23,8 +23,9 @@ class LinePrinter; class MinimalSymbolDumper : public codeview::SymbolVisitorCallbacks { public: MinimalSymbolDumper(LinePrinter &P, bool RecordBytes, + codeview::LazyRandomTypeCollection &Ids, codeview::LazyRandomTypeCollection &Types) - : P(P), Types(Types) {} + : P(P), Ids(Ids), Types(Types) {} Error visitSymbolBegin(codeview::CVSymbol &Record) override; Error visitSymbolBegin(codeview::CVSymbol &Record, uint32_t Offset) override; @@ -37,9 +38,13 @@ public: #include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" private: + std::string typeOrIdIndex(codeview::TypeIndex TI, bool IsType) const; + std::string typeIndex(codeview::TypeIndex TI) const; + std::string idIndex(codeview::TypeIndex TI) const; LinePrinter &P; + codeview::LazyRandomTypeCollection &Ids; codeview::LazyRandomTypeCollection &Types; }; } // namespace pdb diff --git a/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp b/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp index fa9e9612318..560c4ac4f82 100644 --- a/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp +++ b/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp @@ -131,7 +131,7 @@ private: void discoverTypeIndicesInSymbols() { Refs.resize(Symbols.size()); for (uint32_t I = 0; I < Symbols.size(); ++I) - discoverTypeIndices(Symbols[I], Refs[I]); + discoverTypeIndicesInSymbol(Symbols[I], Refs[I]); } // Helper function to write out a field list record with the given list