Skip to content

Commit 651db91

Browse files
committedJul 18, 2017
[PDB] Merge in types and items from type servers (/Zi)
Summary: Object files compiled with /Zi emit type information into a type server PDB. The .debug$S section will contain a single TypeServer2Record with the absolute path and GUID of the type server. LLD needs to load the type server PDB and merge all types and items it finds in it into the destination PDB. Depends on D35495 Reviewers: ruiu, inglorion Subscribers: zturner, llvm-commits Differential Revision: https://reviews.llvm.org/D35504 llvm-svn: 308235
1 parent 67653ee commit 651db91

File tree

7 files changed

+830
-28
lines changed

7 files changed

+830
-28
lines changed
 

‎lld/COFF/PDB.cpp

+143-24
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,29 @@
1414
#include "SymbolTable.h"
1515
#include "Symbols.h"
1616
#include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
17-
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1817
#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
19-
#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
2018
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
2119
#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
20+
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
2221
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
2322
#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
2423
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
2524
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
2625
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
2726
#include "llvm/DebugInfo/MSF/MSFCommon.h"
27+
#include "llvm/DebugInfo/PDB/GenericError.h"
2828
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
2929
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
3030
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
3131
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
3232
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
33+
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
3334
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
3435
#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
3536
#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
3637
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
3738
#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
39+
#include "llvm/DebugInfo/PDB/PDB.h"
3840
#include "llvm/Object/COFF.h"
3941
#include "llvm/Support/BinaryByteStream.h"
4042
#include "llvm/Support/Endian.h"
@@ -53,6 +55,14 @@ using llvm::object::coff_section;
5355
static ExitOnError ExitOnErr;
5456

5557
namespace {
58+
/// Map from type index and item index in a type server PDB to the
59+
/// corresponding index in the destination PDB.
60+
struct CVIndexMap {
61+
SmallVector<TypeIndex, 0> TPIMap;
62+
SmallVector<TypeIndex, 0> IPIMap;
63+
bool IsTypeServerMap = false;
64+
};
65+
5666
class PDBLinker {
5767
public:
5868
PDBLinker(SymbolTable *Symtab)
@@ -68,10 +78,21 @@ class PDBLinker {
6878
/// Link CodeView from a single object file into the PDB.
6979
void addObjectFile(ObjectFile *File);
7080

71-
/// Merge the type information from the .debug$T section in the given object
72-
/// file. Produce a mapping from object file type indices to type or
73-
/// item indices in the final PDB.
74-
void mergeDebugT(ObjectFile *File, SmallVectorImpl<TypeIndex> &TypeIndexMap);
81+
/// Produce a mapping from the type and item indices used in the object
82+
/// file to those in the destination PDB.
83+
///
84+
/// If the object file uses a type server PDB (compiled with /Zi), merge TPI
85+
/// and IPI from the type server PDB and return a map for it. Each unique type
86+
/// server PDB is merged at most once, so this may return an existing index
87+
/// mapping.
88+
///
89+
/// If the object does not use a type server PDB (compiled with /Z7), we merge
90+
/// all the type and item records from the .debug$S stream and fill in the
91+
/// caller-provided ObjectIndexMap.
92+
const CVIndexMap &mergeDebugT(ObjectFile *File, CVIndexMap &ObjectIndexMap);
93+
94+
const CVIndexMap &maybeMergeTypeServerPDB(ObjectFile *File,
95+
TypeServer2Record &TS);
7596

7697
/// Add the section map and section contributions to the PDB.
7798
void addSections(ArrayRef<uint8_t> SectionTable);
@@ -99,6 +120,9 @@ class PDBLinker {
99120
llvm::SmallString<128> NativePath;
100121

101122
std::vector<pdb::SecMapEntry> SectionMap;
123+
124+
/// Type index mappings of type server PDBs that we've loaded so far.
125+
std::map<GUID, CVIndexMap> TypeServerIndexMappings;
102126
};
103127
}
104128

@@ -146,25 +170,114 @@ static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
146170
});
147171
}
148172

149-
void PDBLinker::mergeDebugT(ObjectFile *File,
150-
SmallVectorImpl<TypeIndex> &TypeIndexMap) {
173+
static Optional<TypeServer2Record>
174+
maybeReadTypeServerRecord(CVTypeArray &Types) {
175+
auto I = Types.begin();
176+
if (I == Types.end())
177+
return None;
178+
const CVType &Type = *I;
179+
if (Type.kind() != LF_TYPESERVER2)
180+
return None;
181+
TypeServer2Record TS;
182+
if (auto EC = TypeDeserializer::deserializeAs(const_cast<CVType &>(Type), TS))
183+
fatal(EC, "error reading type server record");
184+
return std::move(TS);
185+
}
186+
187+
const CVIndexMap &PDBLinker::mergeDebugT(ObjectFile *File,
188+
CVIndexMap &ObjectIndexMap) {
151189
ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
152190
if (Data.empty())
153-
return;
154-
155-
// Look for type server PDBs next to the input file. If this file has a parent
156-
// archive, look next to the archive path.
157-
StringRef LocalPath =
158-
!File->ParentName.empty() ? File->ParentName : File->getName();
159-
(void)LocalPath; // FIXME: Implement type server handling here.
191+
return ObjectIndexMap;
160192

161193
BinaryByteStream Stream(Data, support::little);
162194
CVTypeArray Types;
163195
BinaryStreamReader Reader(Stream);
164196
if (auto EC = Reader.readArray(Types, Reader.getLength()))
165197
fatal(EC, "Reader::readArray failed");
166-
if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable, TypeIndexMap, Types))
167-
fatal(Err, "codeview::mergeTypeStreams failed");
198+
199+
// Look through type servers. If we've already seen this type server, don't
200+
// merge any type information.
201+
if (Optional<TypeServer2Record> TS = maybeReadTypeServerRecord(Types))
202+
return maybeMergeTypeServerPDB(File, *TS);
203+
204+
// This is a /Z7 object. Fill in the temporary, caller-provided
205+
// ObjectIndexMap.
206+
if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable,
207+
ObjectIndexMap.TPIMap, Types))
208+
fatal(Err, "codeview::mergeTypeAndIdRecords failed");
209+
return ObjectIndexMap;
210+
}
211+
212+
static Expected<std::unique_ptr<pdb::NativeSession>>
213+
tryToLoadPDB(const GUID &GuidFromObj, StringRef TSPath) {
214+
std::unique_ptr<pdb::IPDBSession> ThisSession;
215+
if (auto EC =
216+
pdb::loadDataForPDB(pdb::PDB_ReaderType::Native, TSPath, ThisSession))
217+
return std::move(EC);
218+
219+
std::unique_ptr<pdb::NativeSession> NS(
220+
static_cast<pdb::NativeSession *>(ThisSession.release()));
221+
pdb::PDBFile &File = NS->getPDBFile();
222+
auto ExpectedInfo = File.getPDBInfoStream();
223+
// All PDB Files should have an Info stream.
224+
if (!ExpectedInfo)
225+
return ExpectedInfo.takeError();
226+
227+
// Just because a file with a matching name was found and it was an actual
228+
// PDB file doesn't mean it matches. For it to match the InfoStream's GUID
229+
// must match the GUID specified in the TypeServer2 record.
230+
if (ExpectedInfo->getGuid() != GuidFromObj)
231+
return make_error<pdb::GenericError>(
232+
pdb::generic_error_code::type_server_not_found, TSPath);
233+
234+
return std::move(NS);
235+
}
236+
237+
const CVIndexMap &PDBLinker::maybeMergeTypeServerPDB(ObjectFile *File,
238+
TypeServer2Record &TS) {
239+
// First, check if we already loaded a PDB with this GUID. Return the type
240+
// index mapping if we have it.
241+
auto Insertion = TypeServerIndexMappings.insert({TS.getGuid(), CVIndexMap()});
242+
CVIndexMap &IndexMap = Insertion.first->second;
243+
if (!Insertion.second)
244+
return IndexMap;
245+
246+
// Mark this map as a type server map.
247+
IndexMap.IsTypeServerMap = true;
248+
249+
// Check for a PDB at:
250+
// 1. The given file path
251+
// 2. Next to the object file or archive file
252+
auto ExpectedSession = tryToLoadPDB(TS.getGuid(), TS.getName());
253+
if (!ExpectedSession) {
254+
consumeError(ExpectedSession.takeError());
255+
StringRef LocalPath =
256+
!File->ParentName.empty() ? File->ParentName : File->getName();
257+
SmallString<128> Path = sys::path::parent_path(LocalPath);
258+
sys::path::append(Path, sys::path::filename(TS.getName()));
259+
ExpectedSession = tryToLoadPDB(TS.getGuid(), Path);
260+
}
261+
if (auto E = ExpectedSession.takeError())
262+
fatal(E, "Type server PDB was not found");
263+
264+
// Merge TPI first, because the IPI stream will reference type indices.
265+
auto ExpectedTpi = (*ExpectedSession)->getPDBFile().getPDBTpiStream();
266+
if (auto E = ExpectedTpi.takeError())
267+
fatal(E, "Type server does not have TPI stream");
268+
if (auto Err = mergeTypeRecords(TypeTable, IndexMap.TPIMap,
269+
ExpectedTpi->typeArray()))
270+
fatal(Err, "codeview::mergeTypeRecords failed");
271+
272+
// Merge IPI.
273+
auto ExpectedIpi = (*ExpectedSession)->getPDBFile().getPDBIpiStream();
274+
if (auto E = ExpectedIpi.takeError())
275+
fatal(E, "Type server does not have TPI stream");
276+
if (auto Err = mergeIdRecords(IDTable, IndexMap.TPIMap, IndexMap.IPIMap,
277+
ExpectedIpi->typeArray()))
278+
fatal(Err, "codeview::mergeIdRecords failed");
279+
280+
return IndexMap;
168281
}
169282

170283
static bool remapTypeIndex(TypeIndex &TI, ArrayRef<TypeIndex> TypeIndexMap) {
@@ -178,16 +291,22 @@ static bool remapTypeIndex(TypeIndex &TI, ArrayRef<TypeIndex> TypeIndexMap) {
178291

179292
static void remapTypesInSymbolRecord(ObjectFile *File,
180293
MutableArrayRef<uint8_t> Contents,
181-
ArrayRef<TypeIndex> TypeIndexMap,
294+
const CVIndexMap &IndexMap,
182295
ArrayRef<TiReference> TypeRefs) {
183296
for (const TiReference &Ref : TypeRefs) {
184297
unsigned ByteSize = Ref.Count * sizeof(TypeIndex);
185298
if (Contents.size() < Ref.Offset + ByteSize)
186299
fatal("symbol record too short");
300+
301+
// This can be an item index or a type index. Choose the appropriate map.
302+
ArrayRef<TypeIndex> TypeOrItemMap = IndexMap.TPIMap;
303+
if (Ref.Kind == TiRefKind::IndexRef && IndexMap.IsTypeServerMap)
304+
TypeOrItemMap = IndexMap.IPIMap;
305+
187306
MutableArrayRef<TypeIndex> TIs(
188307
reinterpret_cast<TypeIndex *>(Contents.data() + Ref.Offset), Ref.Count);
189308
for (TypeIndex &TI : TIs) {
190-
if (!remapTypeIndex(TI, TypeIndexMap)) {
309+
if (!remapTypeIndex(TI, TypeOrItemMap)) {
191310
TI = TypeIndex(SimpleTypeKind::NotTranslated);
192311
log("ignoring symbol record in " + File->getName() +
193312
" with bad type index 0x" + utohexstr(TI.getIndex()));
@@ -292,7 +411,7 @@ static void scopeStackClose(SmallVectorImpl<SymbolScope> &Stack,
292411
}
293412

294413
static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File,
295-
ArrayRef<TypeIndex> TypeIndexMap,
414+
const CVIndexMap &IndexMap,
296415
BinaryStreamRef SymData) {
297416
// FIXME: Improve error recovery by warning and skipping records when
298417
// possible.
@@ -315,7 +434,7 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File,
315434
// Re-map all the type index references.
316435
MutableArrayRef<uint8_t> Contents =
317436
NewData.drop_front(sizeof(RecordPrefix));
318-
remapTypesInSymbolRecord(File, Contents, TypeIndexMap, TypeRefs);
437+
remapTypesInSymbolRecord(File, Contents, IndexMap, TypeRefs);
319438

320439
// Fill in "Parent" and "End" fields by maintaining a stack of scopes.
321440
CVSymbol NewSym(Sym.kind(), NewData);
@@ -358,8 +477,8 @@ void PDBLinker::addObjectFile(ObjectFile *File) {
358477
// type information, file checksums, and the string table. Add type info to
359478
// the PDB first, so that we can get the map from object file type and item
360479
// indices to PDB type and item indices.
361-
SmallVector<TypeIndex, 128> TypeIndexMap;
362-
mergeDebugT(File, TypeIndexMap);
480+
CVIndexMap ObjectIndexMap;
481+
const CVIndexMap &IndexMap = mergeDebugT(File, ObjectIndexMap);
363482

364483
// Now do all live .debug$S sections.
365484
for (SectionChunk *DebugChunk : File->getDebugChunks()) {
@@ -391,7 +510,7 @@ void PDBLinker::addObjectFile(ObjectFile *File) {
391510
File->ModuleDBI->addDebugSubsection(SS);
392511
break;
393512
case DebugSubsectionKind::Symbols:
394-
mergeSymbolRecords(Alloc, File, TypeIndexMap, SS.getRecordData());
513+
mergeSymbolRecords(Alloc, File, IndexMap, SS.getRecordData());
395514
break;
396515
default:
397516
// FIXME: Process the rest of the subsections.

0 commit comments

Comments
 (0)
Please sign in to comment.