]> granicus.if.org Git - llvm/commitdiff
[PDB] Fix linking of function symbols and local variables.
authorZachary Turner <zturner@google.com>
Tue, 8 Aug 2017 18:34:44 +0000 (18:34 +0000)
committerZachary Turner <zturner@google.com>
Tue, 8 Aug 2017 18:34:44 +0000 (18:34 +0000)
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

include/llvm/DebugInfo/CodeView/TypeDeserializer.h
include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h
lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
tools/llvm-pdbutil/DumpOutputStyle.cpp
tools/llvm-pdbutil/MinimalSymbolDumper.cpp
tools/llvm-pdbutil/MinimalSymbolDumper.h
unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp

index 965cdfd85f48961d98e2b2420acf9b799002f28a..23d4f8a5e179cb5d4df9f895dcef1bbc26253849 100644 (file)
@@ -52,6 +52,21 @@ public:
     return Error::success();
   }
 
+  template <typename T>
+  static Expected<T> deserializeAs(ArrayRef<uint8_t> Data) {
+    CVType CVT;
+    CVT.RecordData = Data;
+    MappingInfo I(CVT.content());
+    const RecordPrefix *Prefix =
+        reinterpret_cast<const RecordPrefix *>(Data.data());
+    TypeRecordKind K =
+        static_cast<TypeRecordKind>(uint16_t(Prefix->RecordKind));
+    T Record(K);
+    if (auto EC = deserializeAs<T>(CVT, Record))
+      return std::move(EC);
+    return Record;
+  }
+
   Error visitTypeBegin(CVType &Record) override {
     assert(!Mapping && "Already in a type mapping!");
     Mapping = llvm::make_unique<MappingInfo>(Record.content());
index afe8942159e84d924eed54e8cb9cccce847775e1..c424a09ece890fce4f8388558cb167051635cdf9 100644 (file)
@@ -30,11 +30,17 @@ void discoverTypeIndices(const CVType &Type,
                          SmallVectorImpl<TiReference> &Refs);
 void discoverTypeIndices(const CVType &Type,
                          SmallVectorImpl<TypeIndex> &Indices);
+void discoverTypeIndices(ArrayRef<uint8_t> RecordData,
+                         SmallVectorImpl<TypeIndex> &Indices);
 
 /// Discover type indices in symbol records. Returns false if this is an unknown
 /// record.
-bool discoverTypeIndices(const CVSymbol &Symbol,
-                         SmallVectorImpl<TiReference> &Refs);
+bool discoverTypeIndicesInSymbol(const CVSymbol &Symbol,
+                                 SmallVectorImpl<TiReference> &Refs);
+bool discoverTypeIndicesInSymbol(ArrayRef<uint8_t> RecordData,
+                                 SmallVectorImpl<TiReference> &Refs);
+bool discoverTypeIndicesInSymbol(ArrayRef<uint8_t> RecordData,
+                                 SmallVectorImpl<TypeIndex> &Indices);
 }
 }
 
index 0d935c4472aefa7ef21ff3635762c347ee9f90f8..650f1942b94e7ca00236666aa8b8f0c3e8598bde 100644 (file)
@@ -395,6 +395,7 @@ static bool discoverTypeIndices(ArrayRef<uint8_t> 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<TypeIndex> &Indices) {
-
+static void resolveTypeIndexReferences(ArrayRef<uint8_t> RecordData,
+                                       ArrayRef<TiReference> Refs,
+                                       SmallVectorImpl<TypeIndex> &Indices) {
   Indices.clear();
 
-  SmallVector<TiReference, 4> 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<TypeIndex> Run;
@@ -469,6 +470,18 @@ void llvm::codeview::discoverTypeIndices(const CVType &Type,
   }
 }
 
+void llvm::codeview::discoverTypeIndices(const CVType &Type,
+                                         SmallVectorImpl<TypeIndex> &Indices) {
+  return discoverTypeIndices(Type.RecordData, Indices);
+}
+
+void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
+                                         SmallVectorImpl<TypeIndex> &Indices) {
+  SmallVector<TiReference, 4> Refs;
+  discoverTypeIndices(RecordData, Refs);
+  resolveTypeIndexReferences(RecordData, Refs, Indices);
+}
+
 void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
                                          SmallVectorImpl<TiReference> &Refs) {
   const RecordPrefix *P =
@@ -477,8 +490,26 @@ void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
   ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs);
 }
 
-bool llvm::codeview::discoverTypeIndices(const CVSymbol &Sym,
-                                         SmallVectorImpl<TiReference> &Refs) {
+bool llvm::codeview::discoverTypeIndicesInSymbol(
+    const CVSymbol &Sym, SmallVectorImpl<TiReference> &Refs) {
   SymbolKind K = Sym.kind();
   return ::discoverTypeIndices(Sym.content(), K, Refs);
 }
+
+bool llvm::codeview::discoverTypeIndicesInSymbol(
+    ArrayRef<uint8_t> RecordData, SmallVectorImpl<TiReference> &Refs) {
+  const RecordPrefix *P =
+      reinterpret_cast<const RecordPrefix *>(RecordData.data());
+  SymbolKind K = static_cast<SymbolKind>(uint16_t(P->RecordKind));
+  return ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K,
+                               Refs);
+}
+
+bool llvm::codeview::discoverTypeIndicesInSymbol(
+    ArrayRef<uint8_t> RecordData, SmallVectorImpl<TypeIndex> &Indices) {
+  SmallVector<TiReference, 2> Refs;
+  if (!discoverTypeIndicesInSymbol(RecordData, Refs))
+    return false;
+  resolveTypeIndexReferences(RecordData, Refs, Indices);
+  return true;
+}
index 99dd358fbf945194c8cf11a657f2d0c4d685bce4..73e4a14a8546d10348e0640c21f84d7f41b80bf2 100644 (file)
@@ -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);
index fd186bc5a889c7f46b0f9d6caa1711d6f2e6896f..cc592b724dff59aa621e7ea167345c30c4d7e26e 100644 (file)
@@ -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();
 }
index 5e30959ea9c0d45f58d3a4a079a3fca1e059cc24..a140af74b694a9e19b55abbdb0451c552e364ccb 100644 (file)
@@ -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
index fa9e961231844e4afdac88c2ee8c12f0093a9fbd..560c4ac4f8223641fcab72e4b8c86c9bb04d18d1 100644 (file)
@@ -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