From 59e3ae827dae9d96096c0fb0b8f2e6d636e14b6c Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Tue, 8 Aug 2017 18:34:44 +0000 Subject: [PATCH] [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 llvm-svn: 310394 --- lld/COFF/PDB.cpp | 81 ++++++++++++++++++---- lld/test/COFF/pdb-comdat.test | 8 +-- lld/test/COFF/pdb-invalid-func-type.yaml | 2 +- lld/test/COFF/pdb-procid-remapping.test | 29 ++++++++ lld/test/COFF/pdb-scopes.test | 6 +- lld/test/COFF/pdb-symbol-types.yaml | 2 +- lld/test/COFF/pdb-type-server-simple.test | 4 +- .../llvm/DebugInfo/CodeView/TypeDeserializer.h | 15 ++++ .../llvm/DebugInfo/CodeView/TypeIndexDiscovery.h | 10 ++- llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp | 47 ++++++++++--- llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp | 10 ++- llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp | 28 ++++++-- llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h | 7 +- .../DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp | 2 +- 14 files changed, 207 insertions(+), 44 deletions(-) create mode 100644 lld/test/COFF/pdb-procid-remapping.test diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp index 296ef9c..9b5dc1e 100644 --- a/lld/COFF/PDB.cpp +++ b/lld/COFF/PDB.cpp @@ -17,6 +17,7 @@ #include "llvm/DebugInfo/CodeView/CVDebugRecord.h" #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolSerializer.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" @@ -298,6 +299,7 @@ static bool remapTypeIndex(TypeIndex &TI, ArrayRef TypeIndexMap) { static void remapTypesInSymbolRecord(ObjFile *File, MutableArrayRef Contents, const CVIndexMap &IndexMap, + const TypeTableBuilder &IDTable, ArrayRef TypeRefs) { for (const TiReference &Ref : TypeRefs) { unsigned ByteSize = Ref.Count * sizeof(TypeIndex); @@ -322,11 +324,55 @@ static void remapTypesInSymbolRecord(ObjFile *File, } } -/// MSVC translates S_PROC_ID_END to S_END. -uint16_t canonicalizeSymbolKind(SymbolKind Kind) { - if (Kind == SymbolKind::S_PROC_ID_END) - return SymbolKind::S_END; - return Kind; +static SymbolKind symbolKind(ArrayRef RecordData) { + const RecordPrefix *Prefix = + reinterpret_cast(RecordData.data()); + return static_cast(uint16_t(Prefix->RecordKind)); +} + +/// MSVC translates S_PROC_ID_END to S_END, and S_[LG]PROC32_ID to S_[LG]PROC32 +static void translateIdSymbols(MutableArrayRef &RecordData, + const TypeTableBuilder &IDTable) { + RecordPrefix *Prefix = reinterpret_cast(RecordData.data()); + + SymbolKind Kind = symbolKind(RecordData); + + if (Kind == SymbolKind::S_PROC_ID_END) { + Prefix->RecordKind = SymbolKind::S_END; + return; + } + + // In an object file, GPROC32_ID has an embedded reference which refers to the + // single object file type index namespace. This has already been translated + // to the PDB file's ID stream index space, but we need to convert this to a + // symbol that refers to the type stream index space. So we remap again from + // ID index space to type index space. + if (Kind == SymbolKind::S_GPROC32_ID || Kind == SymbolKind::S_LPROC32_ID) { + SmallVector Refs; + auto Content = RecordData.drop_front(sizeof(RecordPrefix)); + CVSymbol Sym(Kind, RecordData); + discoverTypeIndicesInSymbol(Sym, Refs); + assert(Refs.size() == 1); + assert(Refs.front().Count == 1); + + TypeIndex *TI = + reinterpret_cast(Content.data() + Refs[0].Offset); + // `TI` is the index of a FuncIdRecord or MemberFuncIdRecord which lives in + // the IPI stream, whose `FunctionType` member refers to the TPI stream. + // Note that LF_FUNC_ID and LF_MEMFUNC_ID have the same record layout, and + // in both cases we just need the second type index. + if (!TI->isSimple() && !TI->isNoneType()) { + ArrayRef FuncIdData = IDTable.records()[TI->toArrayIndex()]; + SmallVector Indices; + discoverTypeIndices(FuncIdData, Indices); + assert(Indices.size() == 2); + *TI = Indices[1]; + } + + Kind = (Kind == SymbolKind::S_GPROC32_ID) ? SymbolKind::S_GPROC32 + : SymbolKind::S_LPROC32; + Prefix->RecordKind = uint16_t(Kind); + } } /// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned. @@ -344,10 +390,8 @@ static MutableArrayRef copySymbolForPdb(const CVSymbol &Sym, memset(NewData.data() + Sym.length(), 0, Size - Sym.length()); // Update the record prefix length. It should point to the beginning of the - // next record. MSVC does some canonicalization of the record kind, so we do - // that as well. + // next record. auto *Prefix = reinterpret_cast(Mem); - Prefix->RecordKind = canonicalizeSymbolKind(Sym.kind()); Prefix->RecordLen = Size - 2; return NewData; } @@ -418,6 +462,7 @@ static void scopeStackClose(SmallVectorImpl &Stack, static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjFile *File, const CVIndexMap &IndexMap, + const TypeTableBuilder &IDTable, BinaryStreamRef SymData) { // FIXME: Improve error recovery by warning and skipping records when // possible. @@ -425,11 +470,11 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjFile *File, BinaryStreamReader Reader(SymData); ExitOnErr(Reader.readArray(Syms, Reader.getLength())); SmallVector Scopes; - for (const CVSymbol &Sym : Syms) { + for (CVSymbol Sym : Syms) { // Discover type index references in the record. Skip it if we don't know // where they are. SmallVector TypeRefs; - if (!discoverTypeIndices(Sym, TypeRefs)) { + if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) { log("ignoring unknown symbol record with kind 0x" + utohexstr(Sym.kind())); continue; } @@ -440,13 +485,19 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjFile *File, // Re-map all the type index references. MutableArrayRef Contents = NewData.drop_front(sizeof(RecordPrefix)); - remapTypesInSymbolRecord(File, Contents, IndexMap, TypeRefs); + remapTypesInSymbolRecord(File, Contents, IndexMap, IDTable, TypeRefs); + + // An object file may have S_xxx_ID symbols, but these get converted to + // "real" symbols in a PDB. + translateIdSymbols(NewData, IDTable); + + SymbolKind NewKind = symbolKind(NewData); // Fill in "Parent" and "End" fields by maintaining a stack of scopes. - CVSymbol NewSym(Sym.kind(), NewData); - if (symbolOpensScope(Sym.kind())) + CVSymbol NewSym(NewKind, NewData); + if (symbolOpensScope(NewKind)) scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym); - else if (symbolEndsScope(Sym.kind())) + else if (symbolEndsScope(NewKind)) scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File); // Add the symbol to the module. @@ -516,7 +567,7 @@ void PDBLinker::addObjFile(ObjFile *File) { File->ModuleDBI->addDebugSubsection(SS); break; case DebugSubsectionKind::Symbols: - mergeSymbolRecords(Alloc, File, IndexMap, SS.getRecordData()); + mergeSymbolRecords(Alloc, File, IndexMap, IDTable, SS.getRecordData()); break; default: // FIXME: Process the rest of the subsections. diff --git a/lld/test/COFF/pdb-comdat.test b/lld/test/COFF/pdb-comdat.test index f85dacd..39c7b0e 100644 --- a/lld/test/COFF/pdb-comdat.test +++ b/lld/test/COFF/pdb-comdat.test @@ -46,7 +46,7 @@ CHECK: 60 | S_COMPILE3 [size = 60] CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, language = c CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 CHECK: flags = security checks | hot patchable -CHECK: 120 | S_GPROC32_ID [size = 44] `main` +CHECK: 120 | S_GPROC32 [size = 44] `main` CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 24 CHECK: debug start = 4, debug end = 19, flags = none CHECK: 164 | S_FRAMEPROC [size = 32] @@ -57,7 +57,7 @@ CHECK: 196 | S_END [size = 4] CHECK: 200 | S_GDATA32 [size = 24] `global` CHECK: type = 0x0074 (int), addr = 0000:0000 CHECK: 224 | S_BUILDINFO [size = 8] BuildId = `0x100A` -CHECK: 232 | S_GPROC32_ID [size = 44] `foo` +CHECK: 232 | S_GPROC32 [size = 44] `foo` CHECK: parent = 0, end = 308, addr = 0002:0032, code size = 15 CHECK: debug start = 0, debug end = 14, flags = none CHECK: 276 | S_FRAMEPROC [size = 32] @@ -71,7 +71,7 @@ CHECK: 60 | S_COMPILE3 [size = 60] CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, language = c CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 CHECK: flags = security checks | hot patchable -CHECK: 120 | S_GPROC32_ID [size = 44] `bar` +CHECK: 120 | S_GPROC32 [size = 44] `bar` CHECK: parent = 0, end = 196, addr = 0002:0048, code size = 14 CHECK: debug start = 4, debug end = 9, flags = none CHECK: 164 | S_FRAMEPROC [size = 32] @@ -82,7 +82,7 @@ CHECK: 196 | S_END [size = 4] CHECK: 200 | S_GDATA32 [size = 24] `global` CHECK: type = 0x0074 (int), addr = 0000:0000 CHECK: 224 | S_BUILDINFO [size = 8] BuildId = `0x100D` -CHECK-NOT: S_GPROC32_ID {{.*}} `foo` +CHECK-NOT: S_GPROC32 {{.*}} `foo` CHECK-LABEL: Mod 0002 | `* Linker *`: Reorder the object files and verify that the other table is selected. diff --git a/lld/test/COFF/pdb-invalid-func-type.yaml b/lld/test/COFF/pdb-invalid-func-type.yaml index 686079e..219dd424 100644 --- a/lld/test/COFF/pdb-invalid-func-type.yaml +++ b/lld/test/COFF/pdb-invalid-func-type.yaml @@ -7,7 +7,7 @@ # RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s # CHECK: Mod 0000 | `{{.*}}pdb-invalid-func-type.yaml.tmp.obj`: -# CHECK: 4 | S_GPROC32_ID [size = 44] `main` +# CHECK: 4 | S_GPROC32 [size = 44] `main` # CHECK: parent = 0, end = 80, addr = 0001:0000, code size = 3 # CHECK: 48 | S_FRAMEPROC [size = 32] # CHECK: 80 | S_END [size = 4] diff --git a/lld/test/COFF/pdb-procid-remapping.test b/lld/test/COFF/pdb-procid-remapping.test new file mode 100644 index 0000000..cb61240 --- /dev/null +++ b/lld/test/COFF/pdb-procid-remapping.test @@ -0,0 +1,29 @@ +# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj +# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj +# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ +# RUN: %t1.obj %t2.obj + +# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s + +CHECK: Symbols +CHECK-NEXT: ============================================================ +CHECK-LABEL: Mod 0000 | +CHECK: 92 | S_GPROC32 [size = 44] `main` +CHECK-NEXT: parent = 0, end = 168, addr = 0002:0000, code size = 14 +CHECK-NEXT: type = `0x1004 (int ())`, debug start = 4, debug end = 9, flags = none +CHECK-NEXT: 136 | S_FRAMEPROC [size = 32] +CHECK-NEXT: size = 40, padding size = 0, offset to padding = 0 +CHECK-NEXT: bytes of callee saved registers = 0, exception handler addr = 0000:0000 +CHECK-NEXT: flags = has async eh | opt speed +CHECK-NEXT: 168 | S_END [size = 4] +CHECK-LABEL: Mod 0001 | +CHECK: 92 | S_GPROC32 [size = 44] `foo` +CHECK-NEXT: parent = 0, end = 168, addr = 0002:0016, code size = 6 +CHECK-NEXT: type = `0x1001 (int ())`, debug start = 0, debug end = 5, flags = none +CHECK-NEXT: 136 | S_FRAMEPROC [size = 32] +CHECK-NEXT: size = 0, padding size = 0, offset to padding = 0 +CHECK-NEXT: bytes of callee saved registers = 0, exception handler addr = 0000:0000 +CHECK-NEXT: flags = has async eh | opt speed +CHECK-NEXT: 168 | S_END [size = 4] +CHECK-LABEL: Mod 0002 | +CHECK: 4 | S_OBJNAME [size = 20] sig=0, `* Linker *` diff --git a/lld/test/COFF/pdb-scopes.test b/lld/test/COFF/pdb-scopes.test index 7beb597..2649167 100644 --- a/lld/test/COFF/pdb-scopes.test +++ b/lld/test/COFF/pdb-scopes.test @@ -34,12 +34,12 @@ RUN: lld-link %t-a.obj %t-b.obj -debug -entry:main -nodefaultlib -out:%t.exe -pd RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s CHECK-LABEL: Mod 0000 | `{{.*}}pdb-scopes.test.tmp-a.obj`: -CHECK: 104 | S_GPROC32_ID [size = 44] `g` +CHECK: 104 | S_GPROC32 [size = 44] `g` CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 5 CHECK: debug start = 4, debug end = 4, flags = none CHECK: 180 | S_REGREL32 [size = 16] `x` CHECK: 196 | S_END [size = 4] -CHECK: 200 | S_GPROC32_ID [size = 44] `main` +CHECK: 200 | S_GPROC32 [size = 44] `main` CHECK: parent = 0, end = 384, addr = 0002:0016, code size = 58 CHECK: debug start = 8, debug end = 53, flags = none CHECK: 276 | S_REGREL32 [size = 20] `argc` @@ -56,7 +56,7 @@ CHECK: 380 | S_END [size = 4] CHECK: 384 | S_END [size = 4] CHECK-LABEL: Mod 0001 | `{{.*}}pdb-scopes.test.tmp-b.obj`: -CHECK: 104 | S_GPROC32_ID [size = 44] `f` +CHECK: 104 | S_GPROC32 [size = 44] `f` CHECK: parent = 0, end = 284, addr = 0002:0080, code size = 62 CHECK: debug start = 8, debug end = 57, flags = none CHECK: 180 | S_REGREL32 [size = 16] `x` diff --git a/lld/test/COFF/pdb-symbol-types.yaml b/lld/test/COFF/pdb-symbol-types.yaml index 2ad6f5b..c9f0373 100644 --- a/lld/test/COFF/pdb-symbol-types.yaml +++ b/lld/test/COFF/pdb-symbol-types.yaml @@ -21,7 +21,7 @@ # CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, language = c # CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 # CHECK: flags = security checks | hot patchable -# CHECK: 116 | S_GPROC32_ID [size = 44] `main` +# CHECK: 116 | S_GPROC32 [size = 44] `main` # CHECK: parent = 0, end = 192, addr = 0002:0000, code size = 7 # CHECK: debug start = 0, debug end = 6, flags = none # CHECK: 160 | S_FRAMEPROC [size = 32] diff --git a/lld/test/COFF/pdb-type-server-simple.test b/lld/test/COFF/pdb-type-server-simple.test index c0de4e3..8976d66 100644 --- a/lld/test/COFF/pdb-type-server-simple.test +++ b/lld/test/COFF/pdb-type-server-simple.test @@ -63,7 +63,7 @@ CHECK-LABEL: Symbols CHECK: ============================================================ CHECK-LABEL: Mod 0000 | `{{.*}}a.obj`: CHECK: 4 | S_OBJNAME [size = 40] sig=0, `C:\src\llvm-project\build\a.obj` -CHECK: 104 | S_GPROC32_ID [size = 44] `main` +CHECK: 104 | S_GPROC32 [size = 44] `main` CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 27 CHECK: type = {{.*}}, debug start = 4, debug end = 22, flags = none CHECK: 200 | S_UDT [size = 12] `Foo` @@ -75,7 +75,7 @@ CHECK: 44 | S_COMPILE3 [size = 60] CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, language = c CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 CHECK: flags = security checks | hot patchable -CHECK: 104 | S_GPROC32_ID [size = 44] `g` +CHECK: 104 | S_GPROC32 [size = 44] `g` CHECK: parent = 0, end = 196, addr = 0002:0032, code size = 13 CHECK: type = {{.*}}, debug start = 5, debug end = 12, flags = none CHECK: 148 | S_FRAMEPROC [size = 32] diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeDeserializer.h b/llvm/include/llvm/DebugInfo/CodeView/TypeDeserializer.h index 965cdfd..23d4f8a 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/TypeDeserializer.h +++ b/llvm/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/llvm/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h b/llvm/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h index afe8942..c424a09 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h +++ b/llvm/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/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp index 0d935c4..650f194 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp +++ b/llvm/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/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp b/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp index 99dd358..73e4a14 100644 --- a/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp +++ b/llvm/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/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp index fd186bc..cc592b7 100644 --- a/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp +++ b/llvm/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/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h b/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h index 5e30959..a140af7 100644 --- a/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h +++ b/llvm/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/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp b/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp index fa9e961..560c4ac 100644 --- a/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp +++ b/llvm/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 -- 2.7.4